0

Can anyone suggest a way to have a null std::ostringstream that avoids doing any work on the parameters passed to it with <<?

There are two related posts here Implementing a no-op std::ostream and Printing to nowhere with ostream , so far the most promising solution is https://stackoverflow.com/a/760353/826203 , but while test it

int main() { onullstream os; os << 666; // std::ostringstream & oss = os; // error C2440: 'initializing' : cannot convert from 'onullstream' to 'std::ostringstream &' oss << "hello, world"; } 

however, this could only be used like os<<666, but could not be used as a std::ostringstream &. any way out here?

1
  • 1
    You get an error because std::ostringstream and onullstream are different parts of the inheritance tree. While both inherits from std::ostream they are otherwise unrelated. Instead I think the requirement to use std::ostringstream here is a false requirement, something that you don't really need. For example, if you have a function that you call with the stream you would have it take a std::ostream reference. Then you could pass a std::ostringstream object or a onullstream object. Commented Oct 17, 2016 at 9:21

1 Answer 1

3

The easiest way to create a non-operational stream is to actually not create a custom stream class but rather to disable an existing stream. For example, you can disable formatting to an std::ostream by setting its stream buffer to null:

std::ostringstream out; out.std::ostream::rdbuf(0); // any attempt to write anything to out will fail. 

If you need a stream which successfully fails to format data you can create a stream buffer which doesn't store any bytes and is always successful. However, when using this stream buffer the actually formatting will be performed:

struct nullbuf: std::streambuf { std::streambuf::int_type overflow(std::streambuf::int_type c) { return std::char_traits<char>::not_eof(c); } }; // ... nullbuf buf; std::ostringstream out; out.std::ostream::rdbuf(&buf); 

Note that I would also recommend not to have functions take a std::ostringstream as arguments. Instead, any function which doesn't construct the stream should travel in terms of std::ostream&. If your existing interfaces already take an std::ostringstream you can create a a null stream by deriving from std::ostringstream and setting the stream buffer appropriately:

class onullstream : private virtual nullbuf , public std::ostringstream { public: nullstring() : std::ios(this) , std::ostringstgream() { this->std::ostream::rdbuf(this); } }; 
Sign up to request clarification or add additional context in comments.

7 Comments

thank you! May I ask 1) what do you mean by "the actually formatting will be performed", and 2) why recommend not to take a std::ostringstream as arguments, instead, take std::ostream&?
@athos: sorry, I keep forgetting that the derived streams have overloads for rdbuf() (which are rather misguided). Just direct the call to std::ios-version of the function, e.g.: out.std::ostream::rdbuf(&buf) (likewise for the other version).
@athos: with respect to your other questions: 1. the nullbuf simply eats all characters sent to it. However, since it is successful all characters are produced. That is, when you insert, e.g., an int the int will be transformed into a sequence of chars representing the int's value and the chars won't be used. That is, there is potentially a substantial amount of work done just for ignoring characters! Invalidating the stream fairly forcibly, i.e., setting the stream buffer to 0, causes the stream operations to not convert the value but all operations fail.
@athos: whether the stream failing matters, I don't know - most likely it doesn't: output streams are rarely tested for successful operations. Note, that in all cases the actual arguments are evaluated. For example, when using out << f() the function f() is called but the result isn't used or, at least, the characters are not used. For 2.: formatting generally doesn't care what stream it gets - it could be an std::ostringstream, an std::ofstream, or some other custom stream. Correspondingly, the functions are best off traveling in terms of std::ostream&.
@athos: I also updated the code in the answer (which still haven't compiled - I'm currently using a mobile device. It shoudl be sufficient to direct the compiler to call the base class version of rdbuf().
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.