为什么命名空间内定义的 << 运算符不参与重载解析?

Gre*_*ers 2 c++ namespaces operator-overloading overload-resolution name-lookup

在以下场景中,operator<<函数参与重载解析(当它位于全局命名空间中时):

template <typename T>
std::ostream &operator<<(std::ostream &os, const std::vector<T> &vec) {
    os << '[';
    for (const T &val : vec)
        os << val << ", ";
    return os << "\b\b]";
}
Run Code Online (Sandbox Code Playgroud)

...但是下面,当在名称空间内定义时,它不会:

namespace blah {
    template <typename T>
    std::ostream &operator<<(std::ostream &os, const std::vector<T> &vec) {
        os << '[';
        for (const T &val : vec)
            os << val << ", ";
        return os << "\b\b]";
    }
}
Run Code Online (Sandbox Code Playgroud)

当从 调用时main,如下所示:

int main() {
    std::vector<int> vec{5, 4, 3, 6, 4, 3, 5, 6, 8, 1};
    std::cout << vec << std::endl;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

...编译器无法operator<<在 中定义重载时找到它blah

到底是怎么回事?

编辑:

当使用范围解析运算符调用重载时,一切都可以正常编译:

blah::operator<<(std::cout, vec);
Run Code Online (Sandbox Code Playgroud)

为什么是这样?

Vla*_*cow 5

在第一种情况下,使用非限定名称查找和/或 ADL(参数相关查找)查找,其中包括声明运算符的全局命名空间。

在第二种情况下,将找不到该运算符,因为blah不考虑名称空间进行非限定名称查找。

您可以使用限定名称,例如:

blah::operator <<( std::cout, vec ) << std::endl;
Run Code Online (Sandbox Code Playgroud)

或者,您可以使用using指令将命名空间包含blah在命名空间集中以进行非限定名称查找,如下所示:

using namespace blah;
std::cout << vec << std::endl;
Run Code Online (Sandbox Code Playgroud)