我正在创建一个包含以下部分的记录器:
// #define LOG(x) // for release mode
#define LOG(x) log(x)
log(const string& str);
log(const ostream& str);
有了这样的想法:
LOG("Test");
LOG(string("Testing") + " 123");
stringstream s;
LOG(s << "Testing" << 1 << "two" << 3);
这一切都按预期工作,但当我这样做时:
LOG(stringstream() << "Testing" << 1 << "two" << 3);
不起作用:
void log(const ostream& os)
{
std::streambuf* buf = os.rdbuf();
if( buf && typeid(*buf) == typeid(std::stringbuf) )
{
const std::string& format = dynamic_cast<std::stringbuf&>(*buf).str();
cout << format << endl;
}
}
导致'format'包含垃圾数据,而不是通常正确的字符串。
我认为这是因为&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;运算符比它来自的字符串流更长。
或者我错了?
(为什么string()以这种方式工作?是因为它返回对它自己的引用吗?我假设是的。)
我真的很想这样做,因为在登录发布模式时我会省去额外的分配。
任何以这种方式完成任务的指针或技巧都会受到欢迎。在我的实际解决方案中,我有许多不同的日志功能,它们都比这更复杂。所以我更希望在调用代码中以某种方式实现它。 (如果可能的话,不要修改我的#define)
只是提出一个想法,一个我的实际#defines的例子:
#define LOG_DEBUG_MSG(format, ...) \
LogMessage(DEBUG_TYPE, const char* filepos, sizeof( __QUOTE__( @__VA_ARGS__ )), \
format, __VA_ARGS__)
匹配varargs类似printf的日志函数,它采用char *,string()和ostream()以及采用string(),exception()和HRESULT的非vararg函数。
答案 0 :(得分:7)
我想我看到发生了什么。这会产生预期的输出:
log(std::stringstream() << 1 << "hello");
虽然没有:
log(std::stringstream() << "hello" << 1);
(它写一个十六进制数字,后跟“1”数字)
解释的一些要素:
在上面的代码中,std :: stringstream()创建一个临时(rvalue)。它的生命周期没有问题,因为它必须持续它声明的整个表达式(即,直到调用log()返回)。
在第一个示例中,一切正常,因为首先调用成员运算符&lt;&lt;(int),然后返回的引用可以传递给运算符&lt;&lt;(ostream&amp;,const char *)
在第二个例子中,运算符&lt;&lt;(不能用“std :: stringstream()”作为第一个参数调用,因为这将要求它绑定到非const引用。但是,成员运算符&lt ;&lt;(void *)没问题,因为它是会员。
顺便说一句:为什么不将log()函数定义为:
void log(const std::ostream& os)
{
std::cout << os.rdbuf() << std::endl;
}
答案 1 :(得分:6)
将LOG()
宏更改为:
#define LOG(x) do { std::stringstream s; s << x; log(s.str()); } while(0)
这将允许您在调试日志中使用以下语法,因此您不必手动构造字符串流。
LOG("Testing" << 1 << "two" << 3);
然后将其定义为无需发布,您将无需额外分配。