The following snippet is simplified version of a logger that I use. It extends std::ostringstream
and can be filled using the <<
-operator. Upon destruction all content is written to std::cout
.
Writing (<<
) directly into a temporary object, Logger()
, I would expect it to print that input, however, it only prints the address of something on std::cout
. When writing into a reference of a temporary object, Logger().stream()
, works as expected.
Why is that happening?
Btw, this behavior only occurs in C++98-land (ideone), which I have to use. With C++11 (coliru) and C++14 (ideone) both call variants work as expected. What's different in 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; }
The operator<<
that handles insertion of const char *
is a non-member template:
template< class Traits > basic_ostream<char,Traits>& operator<<(basic_ostream<char,Traits>& os, const char* s);
It takes its stream by non-const (lvalue) reference, which does not bind to temporaries.
In C++98/03, the best viable function is the member operator<<(const void *)
, which prints an address.
In C++11 and later, the library supplies a special operator<<
for rvalue streams:
template< class CharT, class Traits, class T > basic_ostream< CharT, Traits >& operator<<( basic_ostream<CharT,Traits>&& os, const T& value );
which does os << value
and returns os
, essentially performing the output operation on an lvalue stream.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With