C++重载函数名查找错误

C++ Overloaded function name lookup error

我在 C++ 中遇到有关名称查找的奇怪错误。

可以使用以下最小示例重新创建错误:

#include <vector>
#include <iostream>

std::ostream& operator<<(std::ostream& out, const std::vector<int>& a) {
    for (size_t i = 0; i < a.size(); i++) {
        out << a[i] << std::endl;
    }
    return out;
}

namespace Test {

    struct A {
        // Label 1
        friend std::ostream& operator<<(std::ostream& out, const A&) {
            return out << "A" << std::endl;
        }
    };

    struct B {
        void printVector() noexcept {
            std::vector<int> v{1, 2, 3};
            std::cout << v << std::endl; // The error occurs in this line
        }
        // Label 2
        friend std::ostream& operator<<(std::ostream& out, const B&) {
            return out << "B" << std::endl;
        }
    };

}

int main() {
    Test::B().printVector();
}

编译这将导致以下错误消息:

cannot bind 'std::ostream {aka std::basic_ostream<char>}' lvalue to 'std::basic_ostream<char>&&'

您可以在这里自己测试一下:http://cpp.sh/5oya

奇怪的是,如果您分别删除标有 // Label 1 的函数之一,代码编译和运行正常 // Label 2.

我现在的问题是:这是怎么回事?如何修复?

您遇到了 ADL 问题,但我认为名称查找应该已经在全局命名空间中找到了您的重载。 (我还没有具体的 C++ 标准引用来知道编译器是否错误)。 GCC(6.3 版)和 Clang(3.8.0 版)编译器发现重载 here

一种解决方法是将全局运算符的 name 导入到您当前的命名空间中:

std::vector<int> v{1, 2, 3};
using ::operator <<; 
std::cout << v << std::endl;

如此处所示:http://cpp.sh/95kuq

另一种解决方法是显式调用全局重载,例如:

std::vector<int> v{1, 2, 3};
::operator << (std::cout,  v); 
std::cout << std::endl;

如此处所示:http://cpp.sh/4btyq

其他解决方法是在命名空间 std 中重载运算符 <<,而不是在全局命名空间中。(查找将在命名空间范围内找到它)

namespace std
{
    std::ostream& operator<<(std::ostream& out, const std::vector<int>& a) {
        for (size_t i = 0; i < a.size(); i++) {
            out << a[i] << std::endl;
        }
        return out;
    }
}

尝试Here

[编辑]

另一种解决方法,对于不想污染全局命名空间或 std 的清教徒来说,是

...have the insertion operators in the same namespace as the class upon which it operates.

...正如所讨论的 here.

namespace Test
{
    std::ostream& operator<<(std::ostream& out, const std::vector<int>& a) {
        for (size_t i = 0; i < a.size(); i++) {
            out << a[i] << std::endl;
        }
        return out;
    }
}

工作代码here.