运算符<< on template参数类型成员仅在clang中导致错误

时间:2015-11-27 14:44:28

标签: c++ templates g++ language-lawyer clang++

我有这个例子:

#include <iostream>
#include <tuple>
#include <string>

template <typename T>
class A {
public:
    A(const T &t) : m_t(t) {}
    void foo() {
        std::cout << m_t << std::endl;
    }

private:
    T m_t;
};

typedef std::tuple<std::string, std::string> Type;
std::ostream &operator<<(std::ostream &os, const Type &t) {
    os << std::get<0>(t) << " " << std::get<1>(t);
    return os;
}

int main() {
    A<Type> a(Type{"ala", " ma kota"});
    a.foo();
    return 0;
}

与clang ++(3.6)产生:

test_clang.cpp:10:19: error: call to function 'operator<<' that is neither visible in the template definition nor found by argument-dependent lookup
        std::cout << m_t << std::endl;
              ^
test_clang.cpp:26:7: note: in instantiation of member function 'A<std::tuple<std::basic_string<char>, std::basic_string<char> > >::foo' requested here
    a.foo();
      ^
test_clang.cpp:19:15: note: 'operator<<' should be declared prior to the call site
std::ostream &operator<<(std::ostream &os, const Type &t) {

使用C ++ 11和g ++ - 5.2.1使用C ++ 17版本的g ++ - 4.8期间没有发生错误。 clang ++ - 3.6需要在{/ em> std::ostream &operator<<(std::ostream &os, const Type &t)之前定义

从我的角度来看,成员A::foo<T>取决于模板参数类型,在模板定义期间不应使用此类型的m_t。为什么clang有编译错误而g ++没有?

1 个答案:

答案 0 :(得分:1)

std::tuple<std::string, std::string>

让我们看看这种类型的关联命名空间。 [basic.lookup.argdep] /(2.2):

  

其关联的命名空间是   最关联的类的最里面的名称空间。

这将是命名空间std或辅助命令,但肯定不是全局命名空间。

  

此外,如果T是类模板特化,则其关联   名称空间和类还包括:名称空间和类   与提供的模板参数的类型相关联   模板类型参数(模板模板参数除外); [......不适用的规则......]

递归地将上述内容应用于std::string,为关联的命名空间提供了命名空间std(以及辅助命名空间)。当然不是全局命名空间。显然,std::cout可以重复相同的论证,给出相同的结论。

因此 ADL不会查看全局命名空间,这正是中声明重载的地方。

最后,根据[temp.dep.candidate] / 1,名称解析不成功:

enter image description here

海湾合作委员会的行为不符合要求;见#51577