0

我使用宏研究日志记录机制:

#define LOGFATAL 1 // very serious errors
#define TOSTRING(s) dynamic_cast< std::ostringstream & >((std::ostringstream() << s ) ).str()

#define LOG_TRANSFER(t, s) "[" << t << "] " << s

void inline print_log(const char *level, const std::string& value)
{
    std::cout << "[" << timestamp() << "]["<< level << "]" << value << std::endl;
}

#ifdef DEBUGGING
    #define DEBUG_OUT(l, s) print_log(l, TOSTRING(s));
#else
    #define DEBUG_OUT(s, l)
#endif


#if DEBUGGING >= LOGFATAL
    #define LOG_FATAL(s)        DEBUG_OUT("FATAL", s)
#else
    #define LOG_FATAL(s)
#endif

我按照他的方式使用它: LOG_TRACE(LOG_TRANSFER(ptr, "MemoryManager > allocate ")) LOG_TRACE("MemoryManager > size : " << active_list.size() )

gcc 的作用是:

print_log("TRACE", dynamic_cast< std::ostringstream & >((std::ostringstream() << "[" << ptr << "] " << "MemoryManager > allocate " ) ).str());
print_log("TRACE", dynamic_cast< std::ostringstream & >((std::ostringstream() << "MemoryManager > size : " << active_list.size() ) ).str());

这对我来说看起来不错,但我得到以下输出:

[0 s][TRACE]0x80940d40x9988ea8] MemoryManager > allocate 
[0 s][TRACE]0x80941e01

错误在哪里?

4

1 回答 1

4

问题在于:

dynamic_cast< std::ostringstream & >((std::ostringstream() << s )).str()

或更准确地说:

std::ostringstream() << s

原因是表达式std::ostringstream()是一个临时对象,不能在其上调用非成员重载<<,因为所有非成员<<重载都采用第一个参数 as std::ostream&,这是非常量引用。但是临时不能绑定到非常量引用。因此,当您想要 print 时调用一个成员函数,该函数char*被转换为void*并打印地址。

你需要做一些小技巧。将临时对象(右值)转换为引用类型(左值):

std::ostringstream().flush() << s

为什么我会这样打电话flush()??

好吧,您可以在临时对象上调用成员函数。我选择flush()是因为它返回std::ostream&哪个是非常量引用,而这正是我们所需要的。

它的不同之处在于:

std::ostringstream() << "nawaz" ; //it prints the address of "nawaz".
std::ostringstream().flush() << "nawaz" ; //it prints "nawaz"

第一个调用打印地址的成员,第二个调用打印 c 字符串operator<<的非成员。operator<<这就是幕后的区别。

所以试试这个:

dynamic_cast< std::ostringstream & >((std::ostringstream().flush() << s )).str()

那应该行得通。

另外,我建议static_cast在这里,因为您已经知道类型:

static_cast< std::ostringstream & >((std::ostringstream().flush() << s )).str()

它不依赖于 RTTI。

于 2012-08-28T16:15:53.783 回答