Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I invoke the stream operator overload without a stream object?

Tags:

c++

Suppose I want to throw with a string containing information about some object, but the object implementation only has an overload for the stream operator (<<) rather than a cast to string. I want to do something like this:

throw std::runtime_error("Error, encountered invalid value " + x);

where x is an instance of a type which has (<<) overloaded. The above does not work, however, because the + is not overloaded to a type compatible with const char*. If x were a string (or castable to a string) it would work, but instead I have to do this:

std::stringstream s;
s << "Error, encountered invalid value " << x;
throw std::runtime_error(s.str());

How can I get something as concise as the first example without adding any overloads or custom functions. Does the Standard Library provide some features that will help here?

like image 803
quant Avatar asked Sep 28 '22 00:09

quant


People also ask

When<< operator is overloaded in a class it?

To get cout to accept a Date object after the insertion operator, overload the insertion operator to recognize an ostream object on the left and a Date on the right. The overloaded << operator function must then be declared as a friend of class Date so it can access the private data within a Date object.

What is the correct code to overload output operator?

To make this statement compile, we must overload '+' in a class of 'ob1' or make '+' a global function. The operators '<<' and '>>' are called like 'cout << ob1' and 'cin >> ob1'.

How to overload== in c++?

Overloading Binary Operators Suppose that we wish to overload the binary operator == to compare two Point objects. We could do it as a member function or non-member function. To overload as a member function, the declaration is as follows: class Point { public: bool operator==(const Point & rhs) const; // p1.

Can you overload the operator for data type int?

No we cannot overload integer or float types because overloading means to change the working of existing operators or make them to work with objects int is single member not an object.


1 Answers

You can delegate to a function:

template <typename T>
std::string stream(const T& x) {
    std::ostringstream ss;
    ss << x;
    return ss.str();
}

throw std::runtime_error("Error..." + stream(x));

Which is also what boost::lexical_cast does:

throw std::runtime_error("Error..." + boost::lexical_cast<std::string>(x));

Or you can use a temporary stream, which involves having to do a cast since operator<< conventionally returns just a basic_ostream<char>&:

throw std::runtime_error(
    static_cast<std::ostringstream&&>(std::ostringstream{} << "Error..." << x)
    .str() );

Or you can wrap that logic into a separate type which, when streamed, converts the result to a string, for amusement's sake:

struct ToStrT {
    friend std::string operator<<(std::ostream& os, ToStrT ) {
        return static_cast<std::ostringstream&&>(os).str();
    }
};

constexpr ToStrT ToStr{};

throw std::runtime_error(std::ostringstream{} << "Error..." << x << ToStr);
like image 142
Barry Avatar answered Oct 05 '22 08:10

Barry