I have the following class:
namespace {
class MimeLogger : public std::ostringstream
{
public:
MimeLogger()
{}
~MimeLogger()
{
LOGEVENT( logModuleWSE, logEventDebug, logMsgWSETrace1, str() );
}
};
}
When I do this:
MimeLogger() << "Hello " << "World";
The first "Hello "
string is treated as a void*
. If I debug the code, "Hello "
is passed into std::basic_ostream::operator<< (void const*)
and prints as a pointer value, not a string. The second string, "World"
is properly passed into the global overloaded << operator that takes a char const*
.
I expect both usages of the << operator to resolve to the same overload, but this does not happen. Can someone explain, and maybe propose a fix?
Thanks in advance.
I neglected to mention that I'm stuck with C++03, but I'm glad that some people covered both the C++03 and C++11 cases.
C++03: For the expression MimeLogger() << "Hello "
, the template function
template <typename charT, class traits>
std::basic_ostream<charT, traits>& std::operator<< (
std::basic_ostream<charT, traits>& os,
const char* cstr);
is not considered during overload resolution because the temporary MimeLogger()
may not be bound to a non-const reference. The member function overloads do not have this problem because the rules for the implicit parameter do allow binding to a temporary.
If you can use a compiler with support for C++11 rvalue-references, this should work as you intended, because the C++11 library provides an additional overload
template <typename charT, class traits, typename T>
std::basic_ostream<charT, traits>& std::operator<< (
std::basic_ostream<charT, traits>&& os,
const T& x ); // { os << x; return os; }
which allows temporary streams to be used left of <<
as though they were not temporary.
(I did try a test program with g++ and got different results without and with -std=c++0x.)
If you cannot use a C++11 friendly compiler, adding this to the public section of class MimeLogger
is a workaround that will do what you want with C++03:
template<typename T>
MimeLogger& operator<<(const T& x)
{
static_cast<std::ostringstream&>(*this) << x;
return *this;
}
using std::ostringstream::operator<<;
The using-declaration makes sure the member overloads from the standard library are also visible from MimeLogger
. In particular, without it manipulators like std::endl
don't work with the template operator, since std::endl
is itself a function template, and that's too much template type deduction to expect from C++. But things are fine as long as we're sure not to hide the ostream
member that makes the function manipulators work (27.7.3.6.3):
namespace std {
template <typename charT, class traits>
class basic_ostream : /*...*/ {
public:
basic_ostream<charT, traits>& operator<<(
basic_ostream<charT,traits>& (*pf)(basic_ostream<charT,traits>&));
};
}
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