以下代码段是我使用的记录器的简化版本。它扩展std::ostringstream
,可以使用<<
- 运算符填充。销毁后,所有内容都将写入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;
}
答案 0 :(得分:19)
处理operator<<
插入的const char *
是非成员模板:
template< class Traits >
basic_ostream<char,Traits>& operator<<(basic_ostream<char,Traits>& os, const char* s);
它通过非const(左值)引用获取其流,该引用不绑定到临时值。
在C ++ 98/03中,最好的可行功能是成员operator<<(const void *)
,它会打印一个地址。
在C ++ 11及更高版本中,库为rvalue流提供了一个特殊的operator<<
:
template< class CharT, class Traits, class T >
basic_ostream< CharT, Traits >& operator<<( basic_ostream<CharT,Traits>&& os,
const T& value );
执行os << value
并返回os
,基本上对左值流执行输出操作。
答案 1 :(得分: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);
请注意,第一个参数是非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);
效果为os << x
。现在此重载在Logger() << "foo"
中获胜,并转发参数,就像流是左值一样。然后调用先前给出的自由函数。
答案 2 :(得分:5)
C ++ 11添加了non-member operator<<
:#/ p>的重载
template< class CharT, class Traits, class T >
basic_ostream< CharT, Traits >& operator<<( basic_ostream<CharT,Traits>&& os,
const T& value );
现在,您认为自己在Logger()
案件中打电话的运营商是这样的:
template< class Traits >
basic_ostream<char,Traits>& operator<<( basic_ostream<char,Traits>& os,
const char* s );
适用于Logger().stream()
案例,因为这是左值引用,但这对Logger() << "foo"
案例不起作用。 Logger()
无法绑定到左值引用。在那里,唯一可行的重载是member operator<<
:
basic_ostream& operator<<( const void* value );
打印地址。