std::ostringstream operator overload search order? - c++

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.
Update
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>&));
};
}

How about using containment of std::ostringstream ?
class MimeLogger
{
private:
std::ostringstream oss_m;
public:
MimeLogger()
{
}
~MimeLogger()
{
std::cout << __FILE__ << "(" << __LINE__ << "):" << oss_m.str() << "\n";
}
template<typename Type>
MimeLogger& operator<<(const Type& t)
{
oss_m << t;
return *this;
}
};
void LogDemo()
{
MimeLogger logger;
logger << "Hello " << "World!!\n";
MimeLogger() << "Hello " << "StackOverflow!!\n";
}

Related

Template argument deduction failure for manipulators when forwarding to std::ostream <<

I ran into some trouble trying to inherit std::ostream and using a custom operator << which is basically doing some work and then forwarding to std::ostream <<, e.g.:
#include <iostream>
#include <ostream>
struct ostream : std::ostream{
using std::ostream::ostream;
template<typename T>
ostream &operator <<(T &&arg){
//some work...
static_cast<std::ostream&>(*this) << std::forward<T>(arg);
return *this;
}
};
int main(){
ostream cc(std::cout.rdbuf());
cc << "hello world";
//cc << "hello world" << std::endl; //couldn't deduce template parameter `T`
}
The problem is when using manipulators, like in the line I have commented out, gcc complains about [template argument deduction/substitution failed:].
Do I have to set the template type explicitly?, if so how?, because I cannot use the in class std::ostream::operator << due to incompleteness.
Live on Wandbox
Edit
I have just defined the custom operator << as a free function so not inside the class ostream
#include <iostream>
#include <ostream>
struct ostream : std::ostream{
using std::ostream::ostream;
};
template<typename T>
ostream &operator <<(ostream &os, T &&arg)
{
static_cast<std::ostream&>(os) << std::forward<T>(arg);
return os;
}
int main(){
ostream cc(std::cout.rdbuf());
cc << "hello world" << std::endl;
}
and it is working as expected, also for manipulators. Not sure why this makes a difference here, maybe someone could clarify this for me
The problem is that the manipulators are templated, and your class does not provide the information needed for selecting the right template parameters for std::endl. You should overload the operator<< for the manipulators:
struct ostream : std::ostream{
using std::ostream::ostream;
template<typename T>
ostream &operator <<(T &&arg){
//some work...
static_cast<std::ostream&>(*this) << std::forward<T>(arg);
return *this;
}
ostream &operator<<(
std::ostream &(*manip)(std::ostream&)) {
//some work...
static_cast<std::ostream&>(*this) <<manip;
return *this;
}
};
Note that the code in the question failed for the same reason that the following fails:
auto manip = std::endl;
It simply can't deduce the template parameters of endl.
Update
The alternative that makes the ovloading as a free function does not do what one may expect:
template<typename T>
ostream &operator <<(ostream &os, T &&arg)
{
static_cast<std::ostream&>(os) << std::forward<T>(arg);
return os;
}
int main(){
ostream cc(std::cout.rdbuf());
cc << "hello world" << std::endl;
}
The operator that gets std::endl is from the original iostream library. The compiler does not execute the overloaded function in this case, and that's why there is no compilation error.
If you don't want to overload the manipulators, you can provide the template parameters explicitly:
cc << "hello world" << std::endl<char, std::char_traits<char>>;

Enable template only if the return expression is valid

I want to write a wrapper over std::ostream in this style:
#include <iostream>
struct OstreamWrapper {
OstreamWrapper(std::ostream &out) : out(out) {}
template< typename T >
decltype(auto) operator<<(T &&arg) {
return out << std::move< T >(arg);
}
std::ostream &out;
};
int main() {
OstreamWrapper wrap(std::cout);
wrap << "Hello, world!"; // This works
wrap << std::endl; // This does not work
return 0;
}
The problem with this approach is that it does not work (for example) with std::endl, because (as I get it) std::endl is overloaded, and the compiler does not know how to resolve the overload when it evaluates the template.
I believe that this situation can be fixed with some clever SFINAE, but I cannot find something that works. I think I need something like "enable this template only when cout << arg is a well formed expression", but I do not know how to express that.
For example, I tried this:
template< typename T,
typename = decltype(out << arg) >
decltype(auto) operator<<(T &&arg) {
return out << std::move< T >(arg);
}
But this is not ok, because then the template expressions are evaluated, arg is not yet defined.
template< typename T,
typename = decltype(out << std::declval< T >()) >
decltype(auto) operator<<(T &&arg) {
return out << std::move< T >(arg);
}
This compiles, but does not do what I want, because it requires the type T to be known, while my problem actually lies in establishing how to overload its parameter.
I have also tried more obscure conditions based on std::enable_if and std::is_invocable and std::result_of, but they introduced a lot of errors I could not understand and it probably would be pointless to summary here all the attempts.
Is there a way to do this thing properly? Possibly with C++14, so the codebase remains more backward compatbile, but if C++17 is necessary it is ok as well.
You might add overload to force type (and so unique available overload is chosen):
struct OstreamWrapper {
explicit OstreamWrapper(std::ostream &out) : out(out) {}
template< typename T >
decltype(auto) operator<<(T &&arg) {
return out << std::forward<T>(arg);
}
decltype(auto) operator<<(std::ostream& (&arg)(std::ostream&)) {
return out << arg;
}
std::ostream &out;
};
Demo
std::endl is not overloaded. It's a function template that's declared like this:
template< class CharT, class Traits >
std::basic_ostream<CharT, Traits>& endl( std::basic_ostream<CharT, Traits>& os );
The reason it works directly for std::ostream is that the appropriate operator << (the one for stream manipulators) is a regular member function (though generated from the basic_ostream template for char). It expects a concrete manipulator type. Template argument deduction can be used with this parameter type to deduce the arguments of the correct endl specialization.
Since you seem to support only std::ostream, the solution in #Jarod42's answer is the way to go.

How to overload operator << to act like what ostream does

I am on implementing a class, and I'd like to pass some parameters to the instance using <<.
For example,
terminal term;
term << "Hello World!" << '\n';
The code goes below,
class terminal {
template <typename T>
terminal& operator << (T& t) {
std::cout << t;
return *this;
}
};
Basically, I'd like to be a stream instead of being the part of stream. (not cout << term;)
(Sorry for that I forgot to specify my question)
The question is, it worked well with strings, but it compiled failed if there is a number (like int, char, etc).
If we use the example above, the compiler will complain that
Invalid operands to binary expression ('terminal' and 'int')
I would change to the following, in order for sequencing of operator<< (e.g., term << "hello" << std::endl; ) to work:
namespace foo {
class terminal {
std::ostream &strm;
public:
terminal(std::ostream &strm_) : strm(strm_) {}
terminal() : strm(std::cout) {}
template <typename T>
friend std::ostream& operator<<(terminal &term, T const &t);
};
template <typename T>
std::ostream& operator<<(terminal &term, T const &t) {
term.strm << t;
return term.strm;
}
}
Live Demo
The problem is that your operator << takes its argument by reference to non-const, which means it can only bind to lvalues. So things like non-string literals are out. If you do not need to modify the argument, take it by const & instead. The language has a special rule which allows lvalue references to const to bind to rvalues as well.
terminal& operator << (const T& t) {
std::cout << t;
return *this;
}
If you do need to modify the argument, use a different approach than <<. A stream-like interface which would modify the streamed arguments during << would be extremely counterintuitive and a maintenance nightmare.

Partial template specialization of overloaded << operator

I am having trouble to specialize an overloaded << operator template:
The general template is defined as follows:
template<typename DocIdType,typename DocType>
std::ostream & operator << (std::ostream & os,
const Document<DocIdType,DocType> & doc)
{
[...]
}
The general template works fine. Now I want to specialize the second template parameter. I've tried:
template<typename DocIdType>
std::ostream & operator << <DocIdType,std::string> (std::ostream & os,
const Document<DocIdType,std::string> & doc)
{
[...]
}
When I try to compile this piece of code I get the following compiler error:
"C2768: Illegal use of explicit template arguments"
Can somebody tell me what I am doing wrong?
I could be wrong, but off the top of my head I'd say function templates can't be partially specialized.
Even if they could, prefer straight overloading.
See also Why Not Specialize Function Templates? (by Herb Sutter)
See it Live on Coliru
#include <iostream>
#include <string>
template<typename DocIdType,typename DocType>
struct Document {};
template<typename DocIdType>
std::ostream & operator << (std::ostream & os, const Document<DocIdType,std::string> & doc) {
return os << "for string";
}
template<typename DocIdType,typename DocType>
std::ostream & operator << (std::ostream & os, const Document<DocIdType,DocType> & doc) {
return os << "for generic";
}
using namespace std;
int main(int argc, char *argv[])
{
std::cout << Document<struct anything, std::string>() << "\n";
std::cout << Document<struct anything, struct anything_else>() << "\n";
}
Prints
for string
for generic

C++ chaining of the operator << for std::cout like usage [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
std::endl is of unknown type when overloading operator<<
Operator overloading
I'm currently programming a logger class, but the operator<< method causes a compiler error. Here's a minimized version of the class, in file "logger.h":
#include <iostream>
class Logger {
public:
Logger() : m_file(std::cout) {}
template <typename T>
Logger &operator<<(const T &a) {
m_file<<a;
return *this;
}
protected:
std::ostream& m_file;
};
It is included in my main.cpp and works perfecly when I output a string literal:
log << "hi";
However, the following won't compile.
#include "logger.h"
int main() {
Logger log;
log << std::endl;
}
The g++ compiler reports:
src/main.cpp:5: error: no match for 'operator<<' in 'log << std::endl'
Your problem is not about the chain of << , a single log << endl would also cause the problem. It is because std::endl is a template function:
template <class charT, class traits>
basic_ostream<charT,traits>& endl(basic_ostream<charT,traits>& os);
One of the overload of operator<< in basic_ostream is:
template <class charT, class traits = char_traits<charT> >
class basic_ostream : virtual public basic_ios<charT,traits> {
public:
basic_ostream<charT,traits>& operator<<(
basic_ostream<charT,traits>& (*pf)(basic_ostream<charT,traits>&));
//...
};
So the template parameters can be deduced when std::cout<<std::endl is used. However, when the left side is the class Logger, the compile cannot deduce the template parameters of endl. Explicitly give the template parameters can let program compile and work:
#include <iostream>
class Logger
{
public:
std::ostream &m_file;
Logger(std::ostream &o = std::cout):m_file(o){};
template <typename T>
Logger &operator<<(const T &a) {
m_file<<a;
return *this;
}
};
int main()
{
Logger log;
log<<std::endl<char, std::char_traits<char> >;
log<<"hi"<<" stackoverflow"<<std::endl<char, std::char_traits<char> >;
return 0;
}
Or you can add a new overload of operator<< in class Logger to let compiler deduce the template parameters of std::endl:
#include <iostream>
class Logger
{
public:
std::ostream &m_file;
Logger(std::ostream &o = std::cout):m_file(o){};
template <typename T>
Logger &operator<<(const T &a) {
m_file<<a;
return *this;
}
Logger &operator<<(std::ostream& (*pf) (std::ostream&)){
m_file<<pf;
return *this;
}
};
int main()
{
Logger log;
log<<std::endl;
log<<"hi"<<" stackoverflow"<<std::endl;
return 0;
}
Also, if you don't need the output to be flushed immediately, you can use '\n' instead of endl.
The error is caused by std::endl which is a function. Refer to:
std::endl is of unknown type when overloading operator<<