为什么使用运算符<<时需要重载通过模板?

发布于 2024-09-30 18:15:00 字数 2185 浏览 8 评论 0 原文

正如在这个问题中一样,我正在尝试通过使用 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*]
...

As in this question, I'm experimenting to stream via a class using SBRM/RAII, so

SBRM(x) << "test";

could do some extra's in the destructor, but my template knowledge seems to be limited.

What I have (made simpler for clarity) is:

#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;
}

This sort of works:

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

but my main concern is: why does the compiler require me to overload the template when using (non-string) literals?
Are there any tricks to avoid this or am I taking a wrong approach?
Other suggestions are welcome because I now resorted to using a macro for

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

The issue is seen with gcc 4.1.2. and 4.4.3. Without the overloaded functions, I get:

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*]
...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

千纸鹤 2024-10-07 18:15:00

因为您期望一个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&));

这涵盖了所有无参数操纵器

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

Because you’re expecting a non-const argument and literals can never be treated as such. Make the argument const and your troubles will go away:

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

And as David has mentioned in his comment, you need overloads when using manipulators such as endl. Here’s a shot at them:

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

This covers all the parameterless manipulators.

I’m not actually sure how the parametrized manipulators from <iomanip> work but they seem to return a proxy object that can use the generic operator << variant.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文