Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ wrapper class for iostream, use stream modifiers like std::endl with operator<< [duplicate]

I'm currently writing a wrapper for an std::stringstream and i want to forward all the operator<< calls through my class to the std::stringstream. This works just fine now (thanks to this question: wrapper class for STL stream: forward operator<< calls), but there is still one issue with it.

Let's say I have the following code:

class StreamWrapper {
private:
    std::stringstream buffer;
public:
    template<typename T>
    void write(T &t);

    template<typename T>
    friend StreamWrapper& operator<<(StreamWrapper& o, T const& t);

    // other stuff ...
};


template<typename T>
StreamWrapper& operator<<(StreamWrapper& o, T const& t) {
    o.write(t);
    return o;
}

template<typename T>
void StreamWrapper::write(T& t) {
    // other stuff ...

    buffer << t;

    // other stuff ...
}

If I now do this:

StreamWrapper wrapper;
wrapper << "text" << 15 << "stuff";

This works just fine. But if I want to use the stream modifiers like std::endl, which is a function according to http://www.cplusplus.com/reference/ios/endl, I simply doesn't compile.

StreamWrapper wrapper;
wrapper << "text" << 15 << "stuff" << std::endl;

Why? How can I forward the stream modifiers too?

like image 751
MarcDefiant Avatar asked Feb 12 '13 09:02

MarcDefiant


2 Answers

See this answer.

You'll want

typedef std::ostream& (*STRFUNC)(std::ostream&);

StreamWrapper& operator<<(STRFUNC func)  // as a member, othewise you need the additional StreamWrappe& argument first
{
  this->write(func);
  return *this;
}
like image 108
rubenvb Avatar answered Nov 14 '22 14:11

rubenvb


You seem to be doing a bit of extra work. I normally use:

class StreamWrapper
{
    // ...
public:
    template <typename T>
    StreamWrapper& operator<<( T const& obj )
    {
        //  ...
    }
};

With a modern compiler, this should work for all concrete types. The problem is that manipulators are template functions, so the compiler is unable to do template argument type deduction. The solution is to provide non-template overloads for the types of the manipulators:

StreamWrapper& operator<<( std::ostream& (*pf)( std::ostream& ) )
{
    //  For manipulators...
}

StreamWrapper& operator<<( std::basic_ios<char>& (*pf)( std::basic_ios<char>& )
{
    //  For manipulators...
}

Type deduction will fail for the manipulators, but the compiler will pick up these for function overload resolution.

(Note that you might need even more, for things like std::setw(int).)

like image 32
James Kanze Avatar answered Nov 14 '22 12:11

James Kanze