编译以下代码失败,因为第二个函数即使在命名空间之外也找不到第一个。我自己无法解决问题,到目前为止,我在网上都没有找到任何答案。
test.cpp:
#include <bits/stdc++.h>
struct myclass {};
template <typename T, typename U>
std::ostream& operator<< (std::ostream &os, const std::pair<T, U> &p) {
os << "(" << p.first << ", " << p.second << ")";
return os;
}
namespace my {
void operator<< (std::ostream os, myclass m) {
std::cout << std::pair<int, int>(5, 4); // This is line 13.
}
}
int main() {
return 0;
}
编译器(g++ test.cpp -O2 -o test.exe
)给出的错误:
test.cpp:13:13: error: no match for 'operator<<' (operand types are 'std::ostream {aka std::basic_ostream<char>}' and 'std::pair<int, int>')
。
并继续进行,为operator<<
可能提供了很多建议。
观察1:如果两个函数的名称不同,则不会发生错误。
观察2:如果删除了namespace my {
}
,则不会发生任何错误。
答案 0 :(得分:3)
这是一种隐藏名称的方法;函数/运算符不能通过不同的作用域进行重载。
根据name lookup的规则,
(重点是我的)
...,名称查找按如下所述检查范围,直到找到至少一个任何类型的声明,然后查找停止并且不再检查其他范围。
在这种情况下,名称operator<<
在命名空间my
(即本身)的范围内找到,然后名称查找停止,将不检查全局范围,而全局{{1 }}不会考虑以下重载解决方案。
还有
观察1:如果两个函数的名称不同,则不会发生错误。
这很好,因为没有隐藏名称。
观察2:如果删除了我的{}名称空间,则不会发生错误。
这很好,因为两个operator<<
被放在相同的范围内,即全局名称空间。然后可以找到两个operator<<
,然后以超载分辨率进行考虑,最后将选择适当的一个。
如评论所建议,您可以应用operator<<
将全局名称空间中的名称引入名称空间using
中;那么将找到两个my
,然后将其考虑为过载解析。
答案 1 :(得分:1)
在operator<<
中定义的namespace my
可以防止重载解析考虑您在全局名称空间中定义的operator<<
。您只能在此处依赖ADL或在当前范围内带来所需的重载:
namespace my {
std::ostream& operator<<(std::ostream& os, myclass m) {
// Bringing the operator in the global namespace in the current scope
using ::operator<<;
std::cout << std::pair<int, int>(5, 4);
}
}