#include <set>
#include <ostream>
#include <streambuf>
template< typename CharT,
typename Traits = std::char_traits<CharT> >
struct StreamSplitBuffer : std::basic_streambuf<CharT, Traits>
{
typedef std::basic_streambuf<CharT, Traits> streambuf_type;
typedef std::basic_ostream<CharT, Traits> ostream_type;
ostream_type& mOriginal;
streambuf_type* const mBase;
std::set<streambuf_type*> mStreambufs;
public:
StreamSplitBuffer( ostream_type& os ):
mOriginal(os), // no list-initialization syntax for references
mBase{os.rdbuf()}
{
add(mBase);
mOriginal.rdbuf( this );
}
~StreamSplitBuffer()
{
mOriginal.rdbuf( mBase );
}
typedef CharT char_type;
typedef Traits traits_type;
typedef typename std::set<streambuf_type*>::iterator iterator;
typedef typename std::set<streambuf_type*>::const_iterator const_iterator;
iterator begin() { return mStreambufs.begin(); }
iterator end() { return mStreambufs.end(); }
const_iterator begin() const { return mStreambufs.cbegin(); }
const_iterator end() const { return mStreambufs.cend(); }
std::pair<iterator, bool> add( streambuf_type* ptr ) { return mStreambufs.insert(ptr); }
std::pair<iterator, bool> add( ostream_type& ptr ) { return add(ptr.rdbuf()); }
void erase( iterator i ) { mStreambufs.erase(i); }
protected:
virtual typename traits_type::int_type overflow( typename traits_type::int_type c = traits_type::eof() ) override
{
typename traits_type::int_type rval = traits_type::not_eof(c);
if( !traits_type::eq_int_type( rval, c ) ) /// EOF - no characters to be written. Return success.
return rval;
for( auto ptr : *this )
if( traits_type::eq_int_type( ptr->sputc( traits_type::to_char_type(c) ), traits_type::eof() ) )
rval = traits_type::eof(); // if one streambuf returns a value indicating failure, all other streambufs are done and EOF is returned.
return rval;
}
};
#include <iostream>
#include <sstream>
int main()
{
StreamSplitBuffer<char> splitter(std::cout);
std::ostringstream stream;
splitter.add(stream);
std::cout << "Hallo Welt!\nWie gehts?";
std::cout << '\n' << stream.str();
}