Graeme
Graeme

Reputation: 4592

Streaming to Exception Class

I have a Exception base class which defines a stream function:

class Exception
{
public:
    template <typename TData, typename TException>
    TException& stream(const TData& data)
    {
        stream_ << data;
        return *reinterpret_cast<TException*>(this);
    }
};

I have a free function overloading operator<<:

template <typename TData>
Exception& operator<<(Exception& ex, const TData& data) {
    return ex.stream<TData, Exception>(data);
}

I also have dervied exceptions overloading operator<<:

template <typename TData>
CoffeeException& operator<<(CoffeeException& ex, const TData& data) {
    return ex.stream<TData, CoffeeException>(data);
}

I use this like so:

else {
    throw CoffeeException() << "Exception text";
}

When I try to use the class the compiler doesn't see the function, it just suggests the standard stream operators avaiable but doesn't note my Exception or CoffeeException free functions. Does this implementation look correct?

Upvotes: 4

Views: 334

Answers (2)

James Kanze
James Kanze

Reputation: 153929

It looks like the usual problem of trying to bind a temporary to a non-const reference. CoffeeException() << "Exception text" can't bind to your operator<<, because CoffeeException() is a temporary. Just make your operator<< a member:

class CoffeeException : public Exception
{
    //  ...
public:
    template <typename TData>
    CoffeeException& operator<<( TData const& data )
    {
        stream( data );
        return *this;
    }
};

While I'm at it: you definitely don't want the reinterpret_cast at the end of Exception::stream. Using the results of this cast is undefined behavior. It will typically work in cases of single inheritance, but fail where multiple inheritance is involved (but even that isn't guaranteed). The simplest solution is what I've done above (and make Exception::stream return void); alternatively, use static_cast here (which should be legal if the inheritance is defined at the point of instantiation).

Upvotes: 8

D_E
D_E

Reputation: 1196

CoffeeException& operator<<(const CoffeeException& ex, const TData& data);

This reference must be const, because you try pass unnamed object. You can also create temporary object to avoid using const reference.

Upvotes: -1

Related Questions