1

我希望能够为一个对象定义流操作符 ( <<, >>),但要拥有一组以上的操作符,以便我可以根据上下文使用不同的集合。例如,如果我有一个对象如下:

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<<"'";
}

但我看不出如何同时定义这两者。

我正在提交我自己的答案,但我希望其他人过去有理由比我更仔细地考虑这一点,并且最好在大型应用程序中采用有组织的方式来做这件事(因此术语“管理”在问题标题)。

4

3 回答 3

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 );

您可以轻松地将其模板化以在任何类型的对象周围加上引号。

于 2013-05-02T11:07:45.573 回答
2

尽管您提出的解决方案可行,但我强烈建议您不要这样做。运算符重载是一个很容易被误用的强大工具。如果行为不直观和不明显,通常弊大于利。

我建议只使用第一个版本

std::ostream& operator<<(std::ostream& out, const Foo& foo) {
  out<<foo.a;
}

并简单地使用

cout << "'" << fooObject << "'";

而不是提供不同的重载。

这使代码清晰直观,并且更易于调试。

我可以想象using namespace在代码中使用不当会产生许多错误。还有代码重复 - 如果您想向b对象添加另一个成员并打印该成员怎么办。其他人可能会找到其中一个重载,对其进行修改,第一眼看到它可以工作,然后忘记另一个重载。

于 2013-05-02T10:03:13.767 回答
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();
}

使用这种方法,您应该避免在顶层(函数范围之外)使用命名空间,因为这可能会污染并模糊使用所需的运算符。

于 2013-05-02T09:51:43.203 回答