为什么在使用operator<<时需要重载?通过模板?

时间:2010-11-05 13:51:22

标签: c++ templates raii

在这个question中,我正在尝试使用SBRM / RAII通过类进行流式传输,所以

SBRM(x) << "test";

可以在析构函数中做一些额外的操作,但我的模板知识似乎有限。

我所拥有的(为清晰起见更简单)是:

#include <iostream>
#include <sstream>

class SBRM
{
public:
  SBRM(int j) : i(j) {}
  ~SBRM() { std::cout << "SBRM(" << i << "): " << oss.str() << std::endl; }

  template<typename T> SBRM& operator<<(T& in) { oss << in; return *this; }
  // SBRM& operator<<(const long long& in) { oss << std::hex << "0x" << in; return *this; }
  SBRM& operator<<(const double& in) { oss << in; return *this; }
  SBRM& operator<<(const void* in) { oss << in; return *this; }

private:
  int i;
  std::ostringstream oss;
};


int main()
{
  std::string ttt = "world";
  const int i = 3;
  SBRM(1) << "Hello";
  SBRM(2) << ttt;
  SBRM(3) << 0x1234567890123ll; 
  SBRM(4) << &i;
  SBRM(5) << 5;
  SBRM(6) << 0.23;
  SBRM(7) << i;
  SBRM(8) << 5 << ", " << ttt << ", " << &i;
}

这种作品:

SBRM(1): Hello
SBRM(2): world
SBRM(3): 3.20256e+14
SBRM(4): 0xbf8ee444
SBRM(5): 5
SBRM(6): 0.23
SBRM(7): 3
SBRM(8): 5, world, 0xbf8ee444

但我主要担心的是:为什么编译器要求我在使用(非字符串)文字时重载模板?
是否有任何技巧可以避免这种情况,或者我采取了错误的方法? 其他建议是受欢迎的,因为我现在使用宏来

NOT_QUITE_SBRM_MACRO(3, "At least, " << 5 << ", this works");

使用gcc 4.1.2可以看到这个问题。和4.4.3。没有重载函数,我得到:

sbrm-stream.cpp: In function ‘int main()’:
sbrm-stream.cpp:27: error: no match for ‘operator<<’ in ‘SBRM(3) << 320255973458211ll’
sbrm-stream.cpp:10: note: candidates are: SBRM& SBRM::operator<<(T&) [with T = long long int]
sbrm-stream.cpp:28: error: no match for ‘operator<<’ in ‘SBRM(4) << & i’
sbrm-stream.cpp:10: note: candidates are: SBRM& SBRM::operator<<(T&) [with T = const int*]
...

1 个答案:

答案 0 :(得分:12)

因为您期望const 参数,文字永远不会被视为这样。使论证const,你的麻烦将消失:

template<typename T> SBRM& operator<<(T const& in) { oss << in; return *this; }

正如David在评论中提到的那样,在使用endl等操纵符时需要重载。这是他们的一个镜头:

SBRM& operator <<(std::ostream& (*manip)(std::ostream&)) {
    oss << manip; // alternatively: manip(os);
    return *this;
}

// same for:

ostream& operator <<(ios& (*manip)(ios&));
ostream& operator <<(ios_base& (*manip)(ios_base&));

这涵盖了所有parameterless manipulators

我实际上并不确定来自<iomanip>的参数化操纵器是如何工作的,但它们似乎返回了一个可以使用通用operator <<变体的代理对象。