how to find out if output stream chain is ended? - c++

What I am trying to achieve?
How can I find if a stream chain is ended? Look at the function below (all these functions are inside a LogRouter class in this question):
template<typename First, typename... Rest>
void log(const LogLevel &level_, First first_, Rest... rest_) {
sstream << first_ << " ";
log(level_, rest_...);
}
void log(const LogLevel &level_) {
for(auto &route : routes)
route->stream() << sstream.str() << std::endl;
sstream.clear();
sstream.str("");
}
I want to achieve the exact same functionality in the above but using streams. So, when I reach an end of a stream it needs to send the final data to the routes and instead of using
router.log(LogLevel::Alert, "test stream", 15);
I want to be able to use
router.log(LogLevel::Alert) << "test stream " << 15;
What I have tried:
std::ostream operator overloading does not accept packed variables.
going through every single passed value one by one. Like below:
struct LogEnd {};
static LogEnd end() { return LogEnd; }
template<typename T> LogRouter &operator<<(const T &value) {
sstream << value;
return *this;
}
LogRouter &log(const LogLevel &level_) {
currentLogLevel = level_; //had to add another variable
return *this;
}
void operator<<(const LogEnd &end) {
for(auto &route : routes)
route.stream() << sstream.str() << std::endl;
currentLogLevel = LogLevel::None;
}
This gives me what I want syntax wise but I need to call the additional LogRouter::end() at the end of every:
router.log(LogLevel::Alert) << "test stream " << 15 << LogRouter::end();
I have a syntax for std::endl also but it would be best if I can call it without anything in the end.
Question
Is there a way to know an end of a stream chain. Something similar to what you can do when using recursive variadic template function.

You could put the interesting logic into the stream's destructor. Obviously, I would also properly deal with stream rather than cooking up something which somewhat looks like a stream but isn't really a stream:
#include <iostream>
#include <sstream>
#include <string>
class logstream
: private virtual std::stringbuf
, public std::ostream {
std::string level;
public:
logstream(std::string l)
: std::ostream(this)
, level(l) {
}
logstream(logstream&& other)
: std::stringbuf(std::move(other))
, std::ostream(std::move(other))
, level(std::move(other.level)) {
this->rdbuf(0);
}
~logstream() {
std::cout << "do something interesting here("
<< this->level<< ", " << this->str() << ")\n";
}
};
logstream trace() {
return logstream("trace");
}
int main()
{
trace() << "hello, world";
}
The stream buffer used (std::stringbuf in this case but it could also be a custom stream buffer) is made a base class to have it constructed before the std::ostream. In principle it is meant to be a data member but data members are constructed after the base classes. Thus, it is made a private base class instead.
It turns out that std::ostream has a virtual base class (std::ios) which would cause the std::ostream to still be constructed before the std::stringbuf if normal inheritance where used for std::stringbuf. Using virtual inheritance and making the std::stringbuf the first base class makes sure it really is constructed first.

Related

How can I inject a newline when a std::ostream object is std::flush'ed?

How can I minimally wrap a std::ofstream so that any call to sync (std::flush) gets turned into a call to std::endl.
(everything below is an answer to the question "why would you do that?" and is not relevant to the above question)
I have an application which contains a custom std::ostream implementation (which wraps around zmq), let's call it zmq_stream.
This zmq_stream also internally implements a custom streambuffer, and works very nicely.
One of the motivations of this design is that in my unit tests, I can simply swap out the zmq_stream in my unit tests with a regular old std::ostringstream and test the results, completely hiding out the network layer.
One of the features of the application itself is to redirect application output to a file or stdout via a command line flag.
Once again, using a basic switch at startup, I can pass either zmq_stream, std::ofstream or plain old std::cout to my main loop.
This is accomplished something like this:
std::ostream* out;
switch(cond)
{
case 1:
out = &std::cout;
break;
case 2:
out = new ofstream("file");
break;
case 3:
out = new zmq_stream(method, endpoints);
break;
}
main_loop(out);
The usage of zmq_stream is as follows:
zmq_stream out(method, endpoints);
out << "do something " << 42 << " or other";
out << "and another" << std::flush; // <- full constructed buffer is sent over the network
Note: it is by design that I use std::flush and not std::endl when flushing to the network. I do not wish to append a newline to all of my network transmissions. As such, all network outputs by the application use std::flush and not std::endl and changing this is not the correct answer.
Question: while for testing purposes, everything works as expected, for the std::cout and std::ofstream options, I'd like to be able to inject a newline when std::flush is called, so that my network transmissions can be separated into newlines on stdout. This would allow me to pipe them onto the standard posix suite of tooling...
Without this injection, there is no way to determine (aside from timing) where the network boundaries are.
I'm looking for the most minimal possible override here so that I don't have to write out a bunch of new classes. Ideally, overriding the sync() virtual method so that it calls overflow('\n'); and then calls base sync().
However, this is proving to be much more challenging than I expected, so I'm wondering if I'm doing it wrong.
The initial solution I wrote doesn't work because it is a compile time solution and I can't switch on it without re-implementing inheritance (so that the main_loop function gets a base class as a parameter).
Instead, here's the answer to original problem implemented in what appears to be the most minimal way possible.
#include <iostream>
#include <fstream>
#include <iomanip>
typedef std::ostringstream zmq_stream;
template <class T>
class newline_injector_streambuf: public std::basic_streambuf<T> {
public:
using int_type = typename std::basic_streambuf<T>::int_type;
newline_injector_streambuf(std::basic_streambuf<T>& dest) : sink(dest) {}
protected:
virtual int_type sync() override { overflow('\n'); return sink.pubsync(); }
virtual int_type overflow(int_type c) override { return sink.sputc(c); }
std::basic_streambuf<T>& sink;
};
template <class T>
struct newline_injector_stream : public std::basic_ostream<typename T::char_type> {
newline_injector_streambuf<typename T::char_type> buf;
newline_injector_stream(T* file) : buf(*file->rdbuf())
{
std::basic_ostream<typename T::char_type>::rdbuf(&buf);
}
};
void test(std::ostream& out)
{
out << std::setfill('x') << std::setw(10) << "" << std::flush;
out << "Hello, world!" << std::flush << "asdf" << std::endl;
}
int main() {
newline_injector_stream out1(&std::cout);
newline_injector_stream out2(new std::ofstream("test.output", std::ios::out | std::ios::ate));
test(std::cout);
test(out1);
test(out2);
return 0;
}
This is the solution that was devised thanks to #463035818-is-not-a-number's initial answer:
struct zmq_stream;
template<typename T>
struct output_device {
T& output;
output_device(T& backing_stream) : output(backing_stream){}
template <typename U>
output_device& operator<<(const U& u)
{
output << u;
return *this;
}
output_device& operator<<(std::ostream& (*f)(std::ostream&)) {
if constexpr (!std::is_same<T, zmq_stream>::value)
if (f == &std::flush<std::ostream::char_type,std::ostream::traits_type>)
output << "\n";
output << f;
return *this;
}
};
// Usage:
int main()
{
/* prelude code */
auto out1 = output_device(std::cout);
auto out2 = output_device(std::ofstream("filename"));
auto out3 = output_device(zmq_stream(method, endpoints));
out1 << "foo" << std::flush << "bar"; // results in foo\nbar
out2 << "foo" << std::flush << "bar"; // results in foo\nbar
out3 << "foo" << std::flush << "bar"; // results in foobar
}
template <class T>
class separator: public std::basic_streambuf<T> {
public:
using int_type = typename std::basic_streambuf<T>::int_type;
using char_type = typename std::basic_streambuf<T>::char_type;
using traits_type = typename std::basic_streambuf<T>::traits_type;
separator(std::basic_streambuf<T> *dest) : sink(dest) {}
protected:
virtual int_type sync() override {
if (nullptr == sink)
return 1;
//std::basic_streambuf<T>::overflow('\n');
overflow('\n');
return sink->pubsync();
}
virtual int_type overflow(int_type c) override {
if (sink == nullptr)
return 1;
return sink->sputc(c);
}
std::basic_streambuf<T> *sink = nullptr;
};
template <class T> struct newline_injector_stream : public std::basic_ostream<T> {
separator<T> buf;
public:
newline_injector_stream(std::basic_ostream<T> &file) : buf(file.rdbuf())
{
std::basic_ostream<T>::rdbuf(&buf);
}
};
The main_loop function signature now goes from taking a std::ostream* type to a output_device& type.

How to write iostream-like interface to logging library?

I would like to write a convinient interface to my very simple logging library. Take two following pieces of code. The first one is what I do now, the second one is my idea for an intuitive interface:
std::ostringstream stream;
stream<<"Some text "<<and_variables<<" formated using standard string stream"
logger.log(stream.str()); //then passed to the logger
And
logger.convinient_log()<<"Same text "<<with_variables<<" but passed directly";
My thought-design process behind that idea is to return some kind of temporary stringstream-like object from logger.convinient_log() function. That object on destruction (I hope it happens at the end of the line or in a similar, convinient place) would collect string from itself and call an actual logger.log(). The point is I want to process it whole, not term-by-term, so that log() can add eg. prefix and sufix to whole line of text.
I'm very well avare that it might be straight impossible or impossible without some heavy magic. If that's the case, what would be an almost-as-convinient way to do that and how to implement it? I bet on passing some special variable that would force collect-call-logger.log() operation.
If you don't know an exact answer, resources on the topic (eg. extending stringstream) would be also welcome.
This is how Boost.Log works, for example. The basic idea is simple:
struct log
{
log() {
uncaught = std::uncaught_exceptions();
}
~log() {
if (uncaught >= std::uncaught_exceptions()) {
std::cout << "prefix: " << stream.str() << " suffix\n";
}
}
std::stringstream stream;
int uncaught;
};
template <typename T>
log& operator<<(log& record, T&& t) {
record.stream << std::forward<T>(t);
return record;
}
template <typename T>
log& operator<<(log&& record, T&& t) {
return record << std::forward<T>(t);
}
// Usage:
log() << "Hello world! " << 42;
std::uncaught_exceptions() is used to avoid logging an incomplete message if an exception is thrown in the middle.
Here's a class I've togeather a while ago. It sounds like what you're looking for is this. I was able to achieve it without any daunting inheriting of ostreams, stream_buf or anything else. You can write to files, console, sockets, or whatever you want whenever a flush is caught.
It doesn't work with ostream_iterators but handles all of the io_manip functions well.
Usage:
Logger log;
int age = 32;
log << "Hello, I am " << age << " years old" << std::endl;
log << "That's " << std::setbase(16) << age << " years in hex" << std::endl;
log(Logger::ERROR) << "Now I'm logging an error" << std::endl;
log << "However, after a flush/endl, the error will revert to INFO" << std::end;
Implementation
#include <iostream>
#include <sstream>
#include <string>
class Logger
{
public:
typedef std::ostream& (*ManipFn)(std::ostream&);
typedef std::ios_base& (*FlagsFn)(std::ios_base&);
enum LogLevel
{
INFO,
WARN,
ERROR
};
Logger() : m_logLevel(INFO) {}
template<class T> // int, double, strings, etc
Logger& operator<<(const T& output)
{
m_stream << output;
return *this;
}
Logger& operator<<(ManipFn manip) /// endl, flush, setw, setfill, etc.
{
manip(m_stream);
if (manip == static_cast<ManipFn>(std::flush)
|| manip == static_cast<ManipFn>(std::endl ) )
this->flush();
return *this;
}
Logger& operator<<(FlagsFn manip) /// setiosflags, resetiosflags
{
manip(m_stream);
return *this;
}
Logger& operator()(LogLevel e)
{
m_logLevel = e;
return *this;
}
void flush()
{
/*
m_stream.str() has your full message here.
Good place to prepend time, log-level.
Send to console, file, socket, or whatever you like here.
*/
m_logLevel = INFO;
m_stream.str( std::string() );
m_stream.clear();
}
private:
std::stringstream m_stream;
int m_logLevel;
};
Create a custom class derived from std::basic_streambuf to write to your logger, eg:
class LoggerBuf : public std::stringbuf
{
private:
Logger logger;
public:
LoggerBuf(params) : std::stringbuf(), logger(params) {
...
}
virtual int sync() {
int ret = std::stringbuf::sync();
logger.log(str());
return ret;
}
};
And then you can instantiate a std::basic_ostream object giving it a pointer to a LoggerBuf object, eg:
LoggerBuf buff(params);
std::ostream stream(&buf);
stream << "Some text " << and_variables << " formated using standard string stream";
stream << std::flush; // only if you need to log before the destructor is called
Alternatively, derive a custom class from std::basic_ostream to wrap your LoggerBuf class, eg:
class logger_ostream : public std::ostream
{
private:
LoggerBuf buff;
public:
logger_ostream(params) : std:ostream(), buff(params)
{
init(&buff);
}
};
std::logger_ostream logger(params);
logger << "Some text " << and_variables << " formated using standard string stream";
logger << std::flush; // only if you need to log before the destructor is called

Overloading operator<< in C++ with a prefix

I'm working on a logger class in C++ that has the following syntax:
Logger log("mylog.txt");
log << "a string" << " " << 1 << " " << 6.2 << "\n";
And it prints:
a string 1 6.2
This is what my class looks like:
class Logger
{
private:
unique_ptr<ofstream> m_pOutStream;
public:
Logger(std::string sFile) : m_pOutStream(new ofstream(sFile, std::ios::app))
{}
template<typename T>
Logger& operator<< (const T& data)
{
*m_pOutStream << data;
return *this;
}
};
It works fine, but I would also like to add a prefix to every line (e.g. a timestamp).
So when I write:
Logger log("mylog.txt");
log << "a string" << " " << 1 << " " << 6.2 << "\n";
I want something like this to be displayed:
11:59:12 a string 1 6.2
I have thought of a couple of solutions:
1.Keep every input stored in a list/stream and use an extra function to print and then clear the list/stream:
Logger log("mylog.txt");
log << "a string" << " " << 1 << " " << 6.2 << "\n";
log.logd(); // <- this prints and then clears the internal stream/list.
2.Keep every input stored in a list/stream and print everything after a "new line" character is detected. And clear the internal stream/list after that.
Both of these solutions are nice but I'd prefer to use them only as a last resort.
Is there any other/better way to achieve what I want?
Derive a class from std::stringbuf, say LoggerStringBuf, and give it a reference to your output std::ofstream in its constructor. Override the virtual std::stringbuf::sync() method to retrieve a std::string from the base std::stringbuf::str() method and prefix it with a timestamp when writing it to the std::ofstream. This way you generate a new timestamp every time your LoggerStringBuf object is flushed to the std::ofstream for any reason, whether explicitly by std::endl or std::flush, or implicitly by its destructor.
Then have your Logger class derive from std::ostream and initialize it with a LoggerStringBuf object. Then you can stream input values to your Logger and they will be cached in your LoggerStringBuf object until flushed to the std::ofstream. At which time you can prepend timestamps as needed.
For example:
class LoggerStringBuf : public std::stringbuf
{
private:
std::ostream &m_OutStream;
protected:
virtual int sync()
{
int ret = std::stringbuf::sync();
std::string s = str();
str("");
// note sure if the string includes non-flushing
// line breaks. If needed, you can use std::getline()
// to break up the string into multiple lines and
// write a timestamp for each line...
//
m_OutStream << "[timestamp] " << s << std::endl;
return ret;
};
public:
LoggerStringBuf(std::ostream &OutStream)
: std::stringbuf(std::ios_base::out), m_OutStream(OutStream)
{
}
~LoggerStringBuf()
{
sync();
}
};
class Logger : public std::ostream
{
private:
std::ofstream m_OutStream;
LoggerStringBuf m_Buf;
public:
Logger(const std::string &sFile)
: std::ostream(0), m_OutStream(sFile, std::ios::app), m_Buf(m_OutStream)
{
init(&m_Buf);
}
template<typename T>
std::ostream& operator<< (const T& data)
{
return static_cast<std::ostream&>(*this) << data;
}
};
You need to introduce an additional wrapper class for Logger that knows whether the line is starting or being appended.
class Appender
{
Appender(Logger& logger) : os_(os) { }
Appender& operator <<(const T& x) { os_ << x; return *this; }
};
class Logger
{
Appender operator <<(const T& x) { os_ << timestamp() << x; return Appender(os_); }
};
The actual code will be more complicated, but try implementing the following logic.
Add a member_variable bool last_char_was_newline, and use it in the code like this:
template<typename T>
Logger& operator<< (const T& data)
{
if (last_char_was_newline) {
*m_pOutStream << current_time_string();
last_char_was_newline = false;
}
*m_pOutStream << data;
if (last_char(data) == '\n') {
last_char_was_newline = true;
}
return *this;
}
To be more general, you should scan data for embedded newlines, and put the time after each of them as well.
The above pseudo-code is glossing over the tricky part. Since data can be any type, last_char(data) (and the more general scanning of the output for embedded newlines) is non-trivial. A general way to implement it might be to write data to a std::stringstream. Then you can scan this string for newlines, and finally output the string to *m_pOutStream.

<< operator overloading in C++ for logging purposes

I have a C++ class where I place many std::cout statements to print informative text messages about a mass of signals that this class is handling. My intentition is to redirect these text messages to a function named log. In this function, I have flag named mVerbose which defines if the log text should be printed. The content of this function is as follows:
void XXXProxy::log(std::stringstream& ss)
{
if(mVerbose)
{
std::cout << ss;
ss << "";
}
}
Then, the caller code snippet to this function is as follows:
std::stringstream logStr;
logStr << "SE"
<< getAddr().toString()
<< ": WAITING on epoll..."
<< std::endl;
log(logStr);
I would like to overload the << operator in my XXXProxy in a way that I can get rid of creating a std::stringstream object and calling the log function. I want to be able to log the text messages as below and let the << operator aggregate everything into:
<< "SE"
<< getAddr().toString()
<< ": WAITING on epoll..."
<< std::endl;
So I wouldlike to have an member << function that looks like:
void XXXProxy::operator << (std::stringstream& ss)
{
if(mVerbose)
{
std::cout << ss;
ss << "";
}
}
QUESTION
I am relatively a novice C++ developer and get lots of compilation errors when attemting to write the above stated like << operator. Could you please make some suggestions or direct me to some links for me to correctly implement this << operator. Thanks.
If you don't want to use std::cout directly and you want to have your own Log class, you could implement a simple wrapper providing the same interface of std::ostream: operator<<:
class Log {
private:
std::ostream& _out_stream;
//Constructor: User provides custom output stream, or uses default (std::cout).
public: Log(std::ostream& stream = std::cout): _out_stream(stream) {}
//Implicit conversion to std::ostream
operator std::ostream() {
return _out_stream;
}
//Templated operator>> that uses the std::ostream: Everything that has defined
//an operator<< for the std::ostream (Everithing "printable" with std::cout
//and its colleages) can use this function.
template<typename T>
Log& operator<< (const T& data)
{
_out_stream << data;
}
}
So if you implement std::ostream& operator>>(std::ostream& os , const YourClass& object) for your classes, you can use this Log class.
The advantage of this approach is that you use the same mechanism to make std::cout << your_class_object work, and to make the class work with the Log.
Example:
struct Foo
{
int x = 0; //You marked your question as C++11, so in class initializers
//are allowed.
//std::ostream::operator<< overload for Foo:
friend std::ostream& operator<<(std::ostream& os , const Foo& foo)
{
os << foo.x;
}
};
int main()
{
Log my_log;
Foo my_foo;
my_foo.x = 31415;
my_log << my_foo << std::endl; //This prints "31415" using std::cout.
}
Possible improvements:
You could write a extern const of class Log, and make the class implement a singleton. This allows you to access the Log everywhere in your program.
It's common in log outputs to have a header, like Log output (17:57): log message. To do that, you could use std::endl as a sentinel and store a flag that says when the next output is the beginning of a line (the beginning of a log message). Checkout the next answer for a complete and working implementation.
References:
std::ostream
operator<< for std::ostream
std::enable_if
std::is_same
decltype specifier
The timestamp of the example was only that, an example :).
But if you like that, we could try to implement it. Thankfully to C++11 and its STL's big improvements, we have an excellent time/date API: std::chrono
std::chronois based in three aspects:
Clocks
Durations
Time points
Also, chrono provides three types of clocks, std::system_clock, std::steady_clock , and std::high_resolution_clock. In our case, we use std::system_clock (We want access to the date-time, not meassuring precise time intervals).
For more info about std::chrono, checkout this awsome Bo Qian's youtube tutorial.
So if we have to implement a time stamp for our log header, we could do this:
EDIT: Like other good things, C++ templates are good tools until you overuse it.
Our problem was that std::endl is a templated function, so we cannot pass it directly to
annother templated function as parammeter (operator<< in our case), because the compiler cannot deduce std::endl template argumments directly. Thats the recurrent error "unresolved overloaded function type".
But there is a much simpler way to do this: Using an explicit overload of operator<< for std::endl only, and other templated for everything else:
class Log
{
private:
std::ostream& _out_stream;
bool _next_is_begin;
const std::string _log_header;
using endl_type = decltype( std::endl ); //This is the key: std::endl is a template function, and this is the signature of that function (For std::ostream).
public:
static const std::string default_log_header;
//Constructor: User passes a custom log header and output stream, or uses defaults.
Log(const std::string& log_header = default_log_header , std::ostream& out_stream = std::cout) : _log_header( log_header ) , _out_stream( out_stream ) , _next_is_begin( true ) {}
//Overload for std::endl only:
Log& operator<<(endl_type endl)
{
_next_is_begin = true;
_out_stream << endl;
return *this;
}
//Overload for anything else:
template<typename T>
Log& operator<< (const T& data)
{
auto now = std::chrono::system_clock::now();
auto now_time_t = std::chrono::system_clock::to_time_t( now ); //Uhhg, C APIs...
auto now_tm = std::localtime( &now_time_t ); //More uhhg, C style...
if( _next_is_begin )
_out_stream << _log_header << "(" << now_tm->tm_hour << ":" << now_tm->tm_min << ":" << now_tm->tm_sec << "): " << data;
else
_out_stream << data;
_next_is_begin = false;
return *this;
}
};
const std::string Log::default_log_header = "Log entry";
This code snippet works perfectly. I have pushed the complete implementation to my github account.
Reference:
std::chrono
std::chrono::system_clock
std::chrono::system_clock::now()
std::time_t
std::chrono::system_clock::to_time_t()
std::tm
std::localtime()

C++ Using stringstream after << as parameter

Is it possible to write a method that takes a stringstream and have it look something like this,
void method(string str)
void printStringStream( StringStream& ss)
{
method(ss.str());
}
And can be called like this
stringstream var;
printStringStream( var << "Text" << intVar << "More text"<<floatvar);
I looked up the << operator and it looks like it returns a ostream& object but I'm probably reading this wrong or just not implementing it right.
Really all I want is a clean way to concatenate stuff together as a string and pass it to a function. The cleanest thing I could find was a stringstream object but that still leaves much to be desired.
Notes:
I can't use much of c++11 answers because I'm running on Visual Studio 2010 (against my will, but still)
I have access to Boost so go nuts with that.
I wouldn't be against a custom method as long as it cleans up this mess.
Edit:
With #Mooing Duck's answer mixed with #PiotrNycz syntax I achieved my goal of written code like this,
try{
//code
}catch(exception e)
{
printStringStream( stringstream() << "An exception has occurred.\n"
<<" Error: " << e.message
<<"\n If this persists please contact "<< contactInfo
<<"\n Sorry for the inconvenience");
}
This is as clean and readable as I could have hoped for.
Hopefully this helps others clean up writing messages.
Ah, took me a minute. Since operator<< is a free function overloaded for all ostream types, it doesn't return a std::stringstream, it returns a std::ostream like you say.
void printStringStream(std::ostream& ss)
Now clearly, general ostreams don't have a .str() member, but they do have a magic way to copy one entire stream to another:
std::cout << ss.rdbuf();
Here's a link to the full code showing that it compiles and runs fine http://ideone.com/DgL5V
EDIT
If you really need a string in the function, I can think of a few solutions:
First, do the streaming seperately:
stringstream var;
var << "Text" << intVar << "More text"<<floatvar;
printStringStream(var);
Second: copy the stream to a string (possible performance issue)
void printStringStream( ostream& t)
{
std::stringstream ss;
ss << t.rdbuf();
method(ss.str());
}
Third: make the other function take a stream too
Make your wrapper over std::stringstream. In this new class you can define whatever operator << you need:
class SSB {
public:
operator std::stringstream& () { return ss; }
template <class T>
SSB& operator << (const T& v) { ss << v; return *this; }
template <class T>
SSB& operator << (const T* v) { ss << v; return *this; }
SSB& operator << (std::ostream& (*v)(std::ostream&)) { ss << v; return *this; }
// Be aware - I am not sure I cover all <<'s
private:
std::stringstream ss;
};
void print(std::stringstream& ss)
{
std::cout << ss.str() << std::endl;
}
int main() {
SSB ssb;
print (ssb << "Hello" << " world in " << 2012 << std::endl);
print (SSB() << "Hello" << " world in " << 2012 << std::endl);
}
For ease of writing objects that can be inserted into a stream, all these classes overload operator<< on ostream&. (Operator overloading can be used by subclasses, if no closer match exists.) These operator<< overloads all return ostream&.
What you can do is make the function take an ostream& and dynamic_cast<> it to stringstream&. If the wrong type is passed in, bad_cast is thrown.
void printStringStream(ostream& os) {
stringstream &ss = dynamic_cast<stringstream&>(os);
cout << ss.str();
}
Note: static_cast<> can be used, it will be faster, but not so bug proof in the case you passed something that is not a stringstream.
Since you know you've got a stringstream, just cast the return value:
stringstream var;
printStringStream(static_cast<stringstream&>(var << whatever));
Just to add to the mix: Personally, I would create a stream which calls whatever function I need to call upon destruction:
#include <sstream>
#include <iostream>
void someFunction(std::string const& value)
{
std::cout << "someFunction(" << value << ")\n";
}
void method(std::string const& value)
{
std::cout << "method(" << value << ")\n";
}
class FunctionStream
: private virtual std::stringbuf
, public std::ostream
{
public:
FunctionStream()
: std::ostream(this)
, d_function(&method)
{
}
FunctionStream(void (*function)(std::string const&))
: std::ostream(this)
, d_function(function)
{
}
~FunctionStream()
{
this->d_function(this->str());
}
private:
void (*d_function)(std::string const&);
};
int main(int ac, char* av[])
{
FunctionStream() << "Hello, world: " << ac;
FunctionStream(&someFunction) << "Goodbye, world: " << ac;
}
It is worth noting that the first object sent to the temporary has to be of a specific set of types, namely one of those, the class std::ostream knows about: Normally, the shift operator takes an std::ostream& as first argument but a temporary cannot be bound to this type. However, there are a number of member operators which, being a member, don't need to bind to a reference! If you want to use a user defined type first, you need to extract a reference temporary which can be done by using one of the member input operators.