描述
我正在覆盖 << operator
对于 std::ostream
以简化我的代码中的对象显示。
我在定义要显示的对象类型的地方使用不同的命名空间。
这导致我出现编译错误。我找到了解决方法。似乎必须在全局范围内声明覆盖,但我真的不明白为什么。有人可以解释导致错误的原因吗?
错误
main.cpp:22:38: error: no match for ‘operator<<’ (operand types are ‘std::basic_ostream’ and ‘std::vector’)
std::cout <<"printVector = " << data << std::endl;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~
示例代码(不要编译)
这是一个显示错误的虚拟示例。
#include <iostream>
#include <vector>
inline std::ostream&
operator<<(std::ostream& strm, std::vector<uint8_t>& buffer)
{
return strm << "display std::vector<uint8_t>";
}
namespace aNamespace {
enum TestEnum { a, b, c };
inline std::ostream&
operator<<(std::ostream& strm, TestEnum& value)
{
return strm << "display TestEnum";
}
static void printVector ()
{
std::vector<uint8_t> data {1, 12, 56, 241, 128};
std::cout <<"printVector = " << data << std::endl;
}
}
int main()
{
aNamespace::printVector();
return 0;
}
环境
C++11;海湾合作委员会; Linux
示例代码修复(已编辑)
这是为那些感兴趣的人准备的代码修复版本。
#include <iostream>
#include <vector>
inline std::ostream&
operator<<(std::ostream& strm, std::vector<uint8_t>& buffer)
{
return strm << "display std::vector<uint8_t>";
}
namespace aNamespace {
using ::operator<<;
enum class TestEnum { a, b, c };
inline std::ostream&
operator<<(std::ostream& strm, TestEnum value)
{
return strm << "display TestEnum";
}
static void printVector ()
{
std::vector<uint8_t> data {1, 12, 56, 241, 128};
std::cout <<"printVector = " << data << std::endl;
}
}
int main()
{
aNamespace::printVector();
return 0;
}
最佳答案
ADL再次来袭
为了解决运算符重载问题,C++ 使用 Argument Dependent Lookup .简而言之,它将搜索任一参数的命名空间(在本例中为命名空间 std
)和运算符调用的命名空间( aNamespace
),如果没有找到运算符重载,则沿层次结构向上搜索 em>.
命名空间 std
不包含任何匹配的重载,但它包含其他不匹配的重载,因此不搜索父命名空间。
现在,如果命名空间 aNamespace
不包含 operator <<
的任何重载,搜索父 namespace (全局)并找到正确的重载,就像在您的“示例代码修复”示例中一样。
但是,如果它包含 operator <<
的任何重载,即使是不匹配的,查找也不会考虑父命名空间并且无法找到正确的重载。
这就是为什么一些 C++ 专家提倡反对广泛使用命名空间,或者至少将其限制为每个项目的单个命名空间的原因之一(例如参见 Titus Winters 的 this article)。
一个可能的修复方法如您所列,但它本身可能有问题,当编译器将使用 aNamespace::TestEnum
查找重载时.更喜欢在封装其中一个参数的 namespace 中重载运算符。
更好的解决方案是将全局范围内的运算符显式添加到您的命名空间范围或函数范围:
using ::operator<<;
关于c++ - 为什么必须在 C++ 的 `std::ostream& operator<<` 作用域中声明 'global' 覆盖?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67090717/