我有这个例子:
#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 ++没有?
答案 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,名称解析不成功:
海湾合作委员会的行为不符合要求;见#51577。