下面的代码在a::b::print
函数中给出了一个错误:Invalid operands to binary expression ('std::ostream' (aka 'basic_ostream<char>') and 'Foo')
.
如果我注释掉命名空间b
中的operator<<
重载,错误就会消失。但我不明白为什么这会有所不同,因为它与 namspacea
中的operator<<
过载具有不同的签名。这是怎么回事?!
#include <iostream>
class Foo {};
namespace a {
std::ostream &operator<<(std::ostream &os, Foo &foo);
void print(Foo& foo) {
std::cout << foo;
}
namespace b {
std::ostream &operator<<(std::ostream &os, double d); // uncomment to resolve error
void print(Foo& foo) {
std::cout << foo; // error here
}
}
}
由于命名空间b
嵌套在命名空间a
内,因此在b
中声明的名称将隐藏在a
中声明的名称。 当名称查找发生在a::b::print
中时,它会搜索b
,如果找不到要查找的内容,它会继续在a
中搜索。 因此,它确实在b
中找到运算符<<并停止查找,甚至不考虑a
中正确的运算符。 当你注释掉它时,它会在b
中找到它,并继续搜索a
并找到它。 您可以通过在命名空间 b 中添加它来解决此问题:
using a::operator<<;
但是,代码的真正问题是您没有正确使用 ADL(依赖于参数的查找)。 处理用户定义类型的运算符应与其操作的类型位于同一命名空间中。 ADL 的作用是添加额外的命名空间进行搜索,以便调用涉及的任何参数(或模板参数)都会自动考虑其命名空间。 (这就是为什么当您的代码在std
之外时,可以将std
命名空间中提供的运算符用于内置类型。
因此,operator<<
移出命名空间a
,并移入Foo
所在的同一(全局)命名空间。 或者,可能更好的是,Foo
移动到命名空间a
。