2

In my project I use a class class called Message which inherits from std::ostringstream to print out human readable information of other class types.

So its << operator is overloaded several times taking my own class types which I want to print out.

class Message : public ostringstream
{
public:
    Message() {};
    virtual ~Message() {};

    Message& operator <<(const MyTypeA &a) { return *this << a.getStr(); };
    Message& operator <<(const MyTypeB &b) { return *this << b.identifier(); };
    Message& operator <<(const MyTypeC &c) { return *this << c.foo(); };

    // Pass everything unknown down to ostringstream, and always return a Message&
    template<class T>
    Message& operator <<(const T &t)
    {
        (std::ostringstream&)(*this) << t;
        return *this;
    }
};

Without the template

MyTypeA a,b;
Message m;
m << a << "-" << b;

the code would not compile, as (m << a << "-") would return a ostringstream& which would not be able to take 'b'. So I use the template to make sure to always return a Message&.

My Problem:

Message m;
m << "Hello, world" << std::endl;

generates a veeery long compiler error and I do not know why.

Here is a minimalistic "not" compilable example of my problem, and here is the corresponding compiler output.

rralf
  • 1,202
  • 15
  • 27

2 Answers2

8

Do not derive from any of the stream classes to create a new stream! The only reason to derive from std::ostream or std::istream is to create a stream properly set up to use a suitable stream buffer. Instead of deriving from a stream, you should derive from std::streambuf to create a new source or destination. To create output operators for new types you'd overload operator<<() with std::ostream& as first argument and your custom type as second argument. Likewise with std::istream&.

BTW, the problem you encountered is because std::endl is a function template. Trying to pass a function template somewhere requires that the appropriate instantiation can be deduced. Since your output operators don't cover a suitable signature, the instantiation of std::endl can't be deduced. I could state what's needed but that would be pointless as it is the wrong way to go anyway.

Dietmar Kühl
  • 150,225
  • 13
  • 225
  • 380
1

Here is how to make your code compile: http://pastebin.com/xAt5junf

The relevant excerpt:

class Message : public ostringstream
{
public:
    Message() {};
    virtual ~Message() {};
};

ostream& operator <<(ostream &os, const MyTypeA &a) {
    return os << a.getStr();
};

ostream& operator <<(ostream &os, const MyTypeB &b) {
    return os << b.getStr();
};
pts
  • 80,836
  • 20
  • 110
  • 183