为什么在使用operator << via template时需要重载?
问题描述:
在本question,我尝试通过使用SBRM/RAII一类流,所以为什么在使用operator << via template时需要重载?
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*]
...
答
因为你期待一个非const
参数和文字不能作这样的处理。使其论点const
和你的烦恼就会消失:
template<typename T> SBRM& operator<<(T const& in) { oss << in; return *this; }
正如大卫在他的评论中提到,您使用机械手如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 <<
变体的代理对象。
长的问题,简单的答案,但它的作品。谢谢 – stefaanv 2010-11-05 13:58:56
@stefaanv:在事情发展过程中发现问题总是困难得多:)顺便说一下,当通过引用/指针传递时,总是尝试使用'const',并且只有在真正需要时才会将其删除。在这里也可以使用'typename boost :: call_traits :: param_type'来根据最有效的内容(即内置的get传递)来获取值或传递引用。检出:http://www.boost.org/doc/libs/1_44_0/libs/utility/call_traits.htm –
2010-11-05 14:14:13
如果你想处理操纵器,你仍然需要提供重载,但是这只会增加3个带有函数指针的重载(也许它们可以模板化为一个,但我不确定) – 2010-11-05 14:16:46