为什么写入临时字符串流对象只打印对象地址?
Why does writing into temporary string stream object only print object addresses?
以下代码段是我使用的记录器的简化版本。它扩展 std::ostringstream
并且可以使用 <<
运算符填充。销毁后,所有内容都会写入 std::cout
.
直接将 (<<
) 写入一个临时对象,Logger()
,我希望它打印该输入,但是,它只打印 std::cout
上某物的地址。写入临时对象的引用时,Logger().stream()
按预期工作。
为什么会这样?
顺便说一句,此行为仅发生在 C++98 版 (ideone), which I have to use. With C++11 (coliru) and 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;
}
处理 const char *
插入的 operator<<
是一个非成员模板:
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 及更高版本中,库为右值流提供了一个特殊的 operator<<
:
template< class CharT, class Traits, class T >
basic_ostream< CharT, Traits >& operator<<( basic_ostream<CharT,Traits>&& os,
const T& value );
执行 os << value
和 returns os
,本质上是对左值流执行输出操作。
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 );
现在,您认为您在 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 );
打印地址。
相关事实:
Logger()
是右值,但 Logger().stream()
是左值。
接受指针并打印其地址的 operator<<
是 ostream&
的成员,而接受 const char*
的 operator<<
和打印字符串是一个自由函数,
template<class traits>
basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>& out,
const char* s);
请注意,第一个参数是非常量左值引用,因此它不能绑定到右值。因此,如果流是右值,则此重载不可行。因此 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
。现在 this 重载在 Logger() << "foo"
中获胜,并转发参数,就好像流是左值一样。然后调用之前给的free函数
以下代码段是我使用的记录器的简化版本。它扩展 std::ostringstream
并且可以使用 <<
运算符填充。销毁后,所有内容都会写入 std::cout
.
直接将 (<<
) 写入一个临时对象,Logger()
,我希望它打印该输入,但是,它只打印 std::cout
上某物的地址。写入临时对象的引用时,Logger().stream()
按预期工作。
为什么会这样?
顺便说一句,此行为仅发生在 C++98 版 (ideone), which I have to use. With C++11 (coliru) and 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;
}
处理 const char *
插入的 operator<<
是一个非成员模板:
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 及更高版本中,库为右值流提供了一个特殊的 operator<<
:
template< class CharT, class Traits, class T >
basic_ostream< CharT, Traits >& operator<<( basic_ostream<CharT,Traits>&& os,
const T& value );
执行 os << value
和 returns os
,本质上是对左值流执行输出操作。
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 );
现在,您认为您在 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 );
打印地址。
相关事实:
Logger()
是右值,但Logger().stream()
是左值。接受指针并打印其地址的
operator<<
是ostream&
的成员,而接受const char*
的operator<<
和打印字符串是一个自由函数,template<class traits> basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>& out, const char* s);
请注意,第一个参数是非常量左值引用,因此它不能绑定到右值。因此,如果流是右值,则此重载不可行。因此 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
。现在 this 重载在 Logger() << "foo"
中获胜,并转发参数,就好像流是左值一样。然后调用之前给的free函数