我希望能够为一个对象定义流操作符(<<
,>>
),但是要有多个它们,以便我可以根据上下文使用不同的集合。例如,如果我有一个如下对象:
struct Foo {
int a;
};
然后在某些地方我希望能够使用这个
std::ostream& operator<<(std::ostream& out, const Foo& foo) {
out<<foo.a;
}
而在其他人中,我更喜欢使用此
std::ostream& operator<<(std::ostream& out, const Foo& foo) {
out<<"'"<<foo.a<<"'";
}
但我无法看到如何同时定义这两者。
我正在提交自己的答案,但我希望其他人过去有理由比我更多地考虑这个问题,并且最好有一个有组织的方式在大型应用程序中这样做(因此,术语“管理“问题标题”。
答案 0 :(得分:4)
创建一个操纵器:一个简单的代理,它只为替代格式提供一个名称(和一个重载槽)。
// default format
std::ostream& operator<<(std::ostream& out, const Foo& foo) {
return out<<foo.a;
}
// custom format
// helper class
struct print_quoted_manip {
Foo const &ref;
print_quoted_manip( Foo const &in )
: ref( in ) {}
};
// implementation
std::ostream& operator<<( std::ostream& out, print_quoted_manip o )
{ return out << '\'' << o.ref << '\''; }
// the manipulator
print_quoted_manip print_quoted( Foo const &in )
{ return print_quoted_manip( in ); }
// usage
std::cout << print_quoted( my_foo );
您可以轻松地对此进行模板化以在任何类型的对象周围添加引号。
答案 1 :(得分:2)
虽然您提出的解决方案可行,但我强烈建议您不要这样做。运算符重载是一个很容易被滥用的强大工具。如果行为不是直观且明显,那么它往往弊大于利。
我建议只使用第一个版本
std::ostream& operator<<(std::ostream& out, const Foo& foo) {
out<<foo.a;
}
并简单地使用
cout << "'" << fooObject << "'";
而不是提供不同的过载。
这使代码清晰直观,并且更易于调试。
我可以想象在代码中不正确使用using namespace
会产生许多错误。还有代码重复 - 如果要将另一个成员b
添加到对象并打印该对象,该怎么办?其他人可能会发现其中一个重载,修改它,看到它在第一次看起来工作,并忘记其他重载。
答案 2 :(得分:1)
您可以在适当命名的每组运算符周围声明命名空间,然后在需要使用这些特定流运算符的函数中使用该命名空间。例如:
#include <iostream>
#include <string>
struct Foo {
int a;
};
namespace raw_output {
std::ostream& operator<<(std::ostream& out, const Foo& foo) {
out<<foo.a;
}
}
namespace quoted_output {
std::ostream& operator<<(std::ostream& out, const Foo& foo) {
out<<"'"<<foo.a<<"'";
}
}
void do_raw() {
using namespace raw_output;
Foo f = { 7 };
std::cout<<f<<std::endl;
}
void do_quoted() {
using namespace quoted_output;
Foo f = { 7 };
std::cout<<f<<std::endl;
}
void do_raw_and_quoted() {
Foo f = { 7 };
{ // Anonymous scoping to use different ops in the same function scope
using namespace raw_output;
std::cout<<f<<std::endl;
}
{
using namespace quoted_output;
std::cout<<f<<std::endl;
}
}
int main() {
do_raw();
do_quoted();
do_raw_and_quoted();
}
使用这种方法,您应该避免在顶层使用命名空间(在函数范围之外),因为这可能会污染并模糊使用所需的运算符。