U
Der Vorteil mit dem proxy war halt, dass ich den user zwingen konnte, den eintrag abzuschließen (nicht im gezeigten code enthalten, aber sind ja im prinzip nur ein bool finished(false) ; finished=true im op<<(manip) bei std::endl und assert(finished) im dtor).
abgesehen davon halt compile time polymorphie und deshalb entfiel der sonst fällige test auf neuer eintrag oder nicht.
aber habs mittlerweile doch ohne den proxy gemacht weil write sonst eben nur so hässlich zu benutzen geht und zweitens ich keine lust hatte, jede fkt. drei (bzw 2x und einmal nichts machend) mal zu implementieren...
falls es interessiert:
template< class base_stream_t, class preamble_op >
struct logger_t
{
public:
typedef base_stream_t base;
typedef typename base::char_type char_type;
typedef typename base::traits_type traits_type;
typedef typename base::int_type int_type;
typedef typename base::pos_type pos_type;
typedef typename base::off_type off_type;
typedef std::basic_ostream< char_type, traits_type > basic_ostream;
logger_t( const logger_t& rhs ) = delete;
logger_t& operator=( const logger_t& rhs ) = delete;
explicit logger_t( const char* filename, std::ios_base::openmode mode = std::ios_base::out )
: base_stream( filename, mode )
{
*this << "\tCREATED" << std::endl;
}
explicit logger_t( const std::string& filename, std::ios_base::openmode mode = std::ios_base::out )
: base_stream( filename, mode )
{
*this << "\tCREATED" << std::endl;
}
~logger_t()
{
added_streams.clear();
*this << "\tCLOSED\r\n";
}
template< class T >
logger_t& operator<<( const T& x )
{
for( auto i( added_streams.begin() ), e( added_streams.end() ); i != e; ++i )
**i << x;
if( entry_manager.is_new_entry() )
entry_manager.make_new_entry( base_stream );
base_stream << x;
return *this;
}
logger_t& operator<<( basic_ostream&(*manip)(basic_ostream&) )
{
for( auto i( added_streams.begin() ), e( added_streams.end() ); i != e; ++i )
**i << manip;
//correct order: ?begin_entry; manip; ?finish_entry
//otherwise manip affect begin_entry
if( entry_manager.is_new_entry() )
entry_manager.make_new_entry( base_stream );
manip( base_stream );
if( manip == std::endl )
entry_manager.finish_entry();
return *this;
}
logger_t& write( const char_type* str, pos_type length )
{
for( auto i( added_streams.begin() ), e( added_streams.end() ); i != e; ++i )
(*i)->write( str, length );
if( entry_manager.is_new_entry() )
entry_manager.make_new_entry( base_stream );
base_stream.write( str, length );
return *this;
}
void duplicate_to_add( logger_t& other_stream )
{
added_streams.push_back( &other_stream );
}
void duplicate_to_remove( logger_t& other_stream )
{
using std::find;
auto iter_to_del = find( added_streams.begin(), added_streams.end(), &other_stream );
my_assert( iter_to_del != added_streams.end() && "cannot delete non-existing item" );
//dont care for remove not at the end: (very small) vector<pointer>
added_streams.erase( iter_to_del );
}
private:
base_stream_t base_stream;
std::vector< logger_t* > added_streams;
struct entry_manager_t : private preamble_op
{
entry_manager_t() : next_in_is_new_entry( true ) {}
void finish_entry() { next_in_is_new_entry = true; }
bool is_new_entry() const { return next_in_is_new_entry; }
void make_new_entry( base_stream_t& the_stream )
{
this->operator()( the_stream );
next_in_is_new_entry = false;
}
private:
bool next_in_is_new_entry;
};
entry_manager_t entry_manager;
};
//template< class char_type >
//struct logger_dummy_t
//...
bb