![](/img/trans.png)
[英]Overloading the << operator in C++ -why return type is a reference std::ostream&
[英]Why `std::ostream& operator<<` overriding must be declare in 'global' scope in C++?
我正在重写std::ostream
的<< operator
,以简化 object 在我的代码中的显示。 我使用不同的命名空间,在其中定义要显示的 object 类型。
这导致我出现编译错误。 我找到了解决办法。 似乎必须在全局 scope 中声明覆盖,但我真的不明白为什么。 有人可以解释导致错误的原因吗?
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; GCC; 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
),如果未找到运算符重载,则向上层级。
命名空间std
不包含任何匹配的重载,但它包含其他不匹配的重载,因此不搜索父命名空间。
现在,如果命名空间aNamespace
不包含operator <<
的任何重载,则会搜索父命名空间(全局)并找到正确的重载,就像在“示例代码修复”示例中一样。
但是,如果它包含operator <<
的任何重载,即使是不匹配的重载,查找也不会考虑父命名空间,并且无法找到正确的重载。
这就是为什么一些 C++ 专家提倡反对广泛使用命名空间,或者至少将其限制为每个项目使用一个命名空间的原因之一(例如,参见 Titus Winters 的这篇文章)。
一种可能的修复方法是您列出的,但它本身可能有问题,当编译器将使用aNamespace::TestEnum
查找重载时。 更喜欢在封装 arguments 之一的命名空间中具有运算符重载。
更好的解决方案是将全局 scope 中的运算符显式添加到您的命名空间 scope 或 function Z31A1FD140BE4BEF2D5ZA18A:2
using ::operator<<;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.