关于c ++:函数模板中的从属名称查找:clang rejects,gcc接受

Dependent name lookup in function template: clang rejects, gcc accepts

考虑下面的片段:

1
2
3
4
5
6
7
8
9
10
11
12
struct X { };

namespace foo {
    template <class T>
    void bar() { T{} < T{}; }

    void operator<(const X&, const X&) {}
}

int main() {
    foo::bar<X>();
}

这clang rejects GCC代码,接受它。这是一个编译器错误或是错误的,这是一clang吗?


我相信这是一个GCC的bug,归档号为70099。来自[温度下降值]:

In resolving dependent names, names from the following sources are considered:
(1.1) — Declarations that are visible at the point of definition of the template.
(1.2) — Declarations from namespaces associated with the types of the function arguments both from the instantiation context (14.6.4.1) and from the definition context.

在模板的定义点,foo::operator<()不可见,也不在函数参数的关联命名空间中(X的关联命名空间只是全局命名空间::而已)。所以我认为GCC发现foo::operator<是错误的,clang拒绝代码是正确的。


GCC是错误的,clang是正确的。在Clang的兼容性页面中也提到了GCC吞下无效代码的事实。

不合格名称按以下方式查找。

  • 编译器在编写名称的范围内执行非限定查找。对于模板,这意味着查找是在定义模板的位置完成的,而不是在实例化模板的位置。由于此时operator<还没有被声明,不合格查找就找不到。
  • 如果名称像函数一样被调用,那么编译器也会执行与参数相关的查找(ADL)。(有时非限定查找可以抑制ADL;有关详细信息,请参阅[basic.lookup.argdep]第3段。)在ADL中,编译器查看调用的所有参数的类型。当它找到一个类类型时,它会在该类的命名空间中查找该名称;结果是它在这些命名空间中找到的所有声明,加上非限定查找中的声明。但是,编译器在知道所有参数类型之前不会执行ADL。