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.
我在 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.