#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; }
与cl(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) {
在g -4.8与C 11和g -5.2.1与C 17建立没有错误发生. cl -3.6需要在A :: foo< T>之前定义std :: ostream& operator<(std :: ostream& os,const Type& t). 从我的角度看,成员m_t取决于模板参数类型,并使用运算符<<在模板定义期间不需要这种类型.为什么cl声有编译错误?
解决方法
std::tuple<std::string,std::string>
我们来看看这个类型的关联命名空间. [basic.lookup.argdep] /(2.2):
Its associated namespaces are the
innermost enclosing namespaces of its associated classes.
这将是命名空间标准或辅助命名空间,但肯定不是全局命名空间.
Furthermore,if
T
is a class template specialization,its associated
namespaces and classes also include: the namespaces and classes
associated with the types of the template arguments provided for
template type parameters (excluding template template parameters); [… inapplicable rules…]
递归地将上述应用到std :: string为相关联的命名空间提供命名空间std(以及辅助的).当然不是全局命名空间.显然,对于std :: cout可以重复相同的论证,得出相同的结论.
因此,ADL将不会查看全局命名空间,这正是您的重载被声明的地方.
最后,根据[temp.dep.candidate] / 1,名称解析失败:
GCC在这里表现不一致见#51577.