6

我正在创建一个包含以下部分的记录器:

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

导致“格式”包含垃圾数据而不是通常的正确字符串。

我认为这是因为 << 运算符返回的临时 ostream 超过了它来自的字符串流。

还是我错了?

(为什么 string() 以这种方式工作?是因为它返回对自身的引用吗?我假设是的。)

我真的很想这样做,因为我会在登录发布模式时消除额外的分配。

任何以这种方式完成它的指针或技巧都将受到欢迎。在我的实际解决方案中,我有许多不同的日志功能,它们都比这更复杂。所以我希望在调用代码中以某种方式实现它。(如果可能,不要修改我的#define)

只是给出一个想法,我的一个实际#defines的一个例子:

#define LOG_DEBUG_MSG(format, ...) \
  LogMessage(DEBUG_TYPE, const char* filepos, sizeof( __QUOTE__( @__VA_ARGS__ )), \
  format, __VA_ARGS__)

它匹配采用 char*、string() 和 ostream() 的 varargs printf-like log 函数以及采用 string()、exception() 和 HRESULT 的非 vararg 函数。

4

2 回答 2

7

我明白发生了什么。这会产生预期的输出:

log(std::stringstream() << 1 << "hello");

虽然这不是:

log(std::stringstream() << "hello" << 1);

(它写入一个十六进制数字,后跟“1”数字)

解释的几个要素:

  • 右值不能绑定到非常量引用
  • 可以临时调用成员函数
  • std::ostream 有一个成员 operator<<(void*)
  • std::ostream 有一个成员 operator<<(int)
  • 对于 char* 运算符不是成员,它是 operator<<(std::ostream&, const char*)

在上面的代码中,std::stringstream() 创建了一个临时的(右值)。它的生命周期没有问题,因为它必须持续到它被声明为的整个完整表达式(即,直到对 log() 的调用返回)。

在第一个示例中,一切正常,因为首先调用了成员 operator<<(int),然后可以将返回的引用传递给 operator<<(ostream&, const char*)

在第二个示例中,不能使用“std::stringstream()”作为第一个参数调用 operator<<(,因为这需要将其绑定到非常量引用。但是,成员 operator<<(void *) 可以,因为它是会员。

顺便说一句:为什么不将 log() 函数定义为:

void log(const std::ostream& os)
{
    std::cout << os.rdbuf() << std::endl;
}
于 2009-10-09T18:01:56.843 回答
6

将您的LOG()宏更改为:

#define LOG(x) do { std::stringstream s; s << x; log(s.str()); } while(0)

这将允许您在调试日志中使用以下语法,因此您不必手动构造字符串流。

LOG("Testing" << 1 << "two" << 3);

然后将其定义为无释放,您将没有额外的分配。

于 2009-10-08T22:34:46.487 回答