模板参数类型成员上的运算符 << 仅在 clang 中导致错误

Operator << on template argument type member causes error only in 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++-4.8 和使用 C++17 的 g++-5.2.1 期间没有发生错误。 clang++-3.6 需要在A::foo<T>.

之前定义std::ostream &operator<<(std::ostream &os, const Type &t)

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

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

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

Its associated namespaces are the innermost enclosing namespaces of its associated classes.

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

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