以下代码段是我使用的记录器的简化版本.它扩展std::ostringstream并可以使用<<-operator 填充.销毁后,所有内容都会写入std::cout.
将(<<)直接写入临时对象,Logger()我希望它能打印输入,但是,它只打印某些东西的地址std::cout.写入临时对象的引用时Logger().stream(),按预期工作.
为什么会这样?
顺便说一句,这种行为只发生在我必须使用的C++ 98-land(ideone)中.使用C++ 11(coliru)和C++ 14(ideone)时,两个调用变量都按预期工作.C++ 11/14有什么不同?
#include <iostream>
#include <sstream>
class Logger : public std::ostringstream
{
public:
~Logger()
{
std::cout << this->str() << std::endl;
}
Logger& stream()
{
return *this;
}
};
int main( int argc, char ** argv )
{
// 1.
// Prints an address, e.g. 0x106e89d5c.
Logger() << "foo";
// 2.
// Works as expected.
Logger().stream() << "foo";
// What is the difference between 1. and 2.?
return 0;
}
Run Code Online (Sandbox Code Playgroud)
T.C*_*.C. 19
在operator<<该处理的插入const char *是一个非成员模板:
template< class Traits >
basic_ostream<char,Traits>& operator<<(basic_ostream<char,Traits>& os, const char* s);
Run Code Online (Sandbox Code Playgroud)
它通过非const(左值)引用获取其流,该引用不绑定到临时值.
在C++ 98/03中,最好的可行功能是成员operator<<(const void *),它打印一个地址.
在C++ 11及更高版本中,库operator<<为rvalue流提供了一个特殊的:
template< class CharT, class Traits, class T >
basic_ostream< CharT, Traits >& operator<<( basic_ostream<CharT,Traits>&& os,
const T& value );
Run Code Online (Sandbox Code Playgroud)
执行os << value和返回os,基本上在左值流上执行输出操作.
Bri*_*ian 11
相关事实:
Logger()是Logger().stream()左值,但是左值.的operator<<,需要一个指针和输出其地址是一个成员ostream&,而operator<<采用一个const char*,并打印该字符串是一个免费的功能,
template<class traits>
basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>& out,
const char* s);
Run Code Online (Sandbox Code Playgroud)请注意,第一个参数是非const左值引用,因此它不能绑定到右值.因此,如果流是右值,则此过载不可行.因此const char*转换为const void*并打印其地址.使用时Logger().stream(),这是一个左值,这个重载会赢,并打印字符串.
在C++ 11中,添加了一个新的右值流插入运算符:
template <class charT, class traits, class T>
basic_ostream<charT, traits>&
operator<<(basic_ostream<charT, traits>&& os, const T& x);
Run Code Online (Sandbox Code Playgroud)
有效果os << x.现在这个重载获胜Logger() << "foo",并转发参数,就像流是左值一样.然后调用先前给出的自由函数.
C++ 11添加了这个重载non-member operator<<:
template< class CharT, class Traits, class T >
basic_ostream< CharT, Traits >& operator<<( basic_ostream<CharT,Traits>&& os,
const T& value );
Run Code Online (Sandbox Code Playgroud)
现在,你认为你正在调用的运营商Logger()是这样的:
template< class Traits >
basic_ostream<char,Traits>& operator<<( basic_ostream<char,Traits>& os,
const char* s );
Run Code Online (Sandbox Code Playgroud)
这适用于这种Logger().stream()情况,因为这是一个左值引用,但这不适用于Logger() << "foo"大小写.Logger()无法绑定到左值引用.在那里,唯一可行的重载是成员 operator<<:
basic_ostream& operator<<( const void* value );
Run Code Online (Sandbox Code Playgroud)
打印地址.