功能模板中的从属名称查找:clang rejects,gcc接受

时间:2016-03-05 19:37:14

标签: c++ templates language-lawyer

考虑以下片段:

struct X { };

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

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

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

clang拒绝此代码,gcc接受它。这是一个gcc bug还是这个clang bug?

2 个答案:

答案 0 :(得分:6)

我认为这是一个gcc bug,归档为70099。来自[temp.dep.res]:

  

在解析依赖名称时,会考虑以下来源的名称:
  (1.1) - 在模板定义时可见的声明   (1.2) - 来自实例化上下文(14.6.4.1)和定义上下文中与函数参数类型相关联的名称空间的声明。

foo::operator<()在模板定义时不可见,并且不在函数参数(X相关命名空间的关联命名空间中只是全局命名空间::)。所以我认为gcc找错foo::operator<是错误的,并且clang拒绝代码是正确的。

答案 1 :(得分:5)

GCC错了Clang是对的。在CLANG的兼容性页面here中也提到了GCC吞下无效代码的事实。

通过以下方式查找不合格的名称。

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