Хорошей новостью является то, что C ++ iostreams очень настраиваемы.Плохая новость в том, что интерфейс немного странный.
#include <iostream>
class scoped_streambuf : public std::streambuf {
std::streambuf *sb;
size_t tabs;
bool at_nl;
virtual int_type overflow( int_type c = traits_type::eof() ) {
if ( at_nl ) for ( size_t t = 0; t < tabs; ++ t ) {
int_type r = sb->sputc( '\t' );
if ( r == traits_type::eof() ) return r;
}
int_type r = sb->sputc( c );
if ( r == traits_type::eof() ) return r;
at_nl = c == '\n';
return c;
}
virtual int sync() { return sb->pubsync(); }
static void uninstall( std::ios_base::event what, std::ios_base &ios, int ) {
if ( what != std::ios_base::erase_event ) return;
std::ostream &os = dynamic_cast< std::ostream & >( ios );
scoped_streambuf *this_ = static_cast< scoped_streambuf * >( os.rdbuf() );
os.rdbuf( this_->sb );
delete this_;
}
public:
scoped_streambuf( std::ostream &inos )
: sb( inos.rdbuf( this ) ), tabs(), at_nl() {
inos.register_callback( &uninstall, 0 );
}
friend std::ostream &indent( std::ostream &os ) {
++ dynamic_cast< scoped_streambuf & >( * os.rdbuf() ).tabs;
return os;
}
friend std::ostream &outdent( std::ostream &os ) {
-- dynamic_cast< scoped_streambuf & >( * os.rdbuf() ).tabs;
return os;
}
};
std::ostream &indent( std::ostream & );
std::ostream &outdent( std::ostream & );
struct indent_scope {
std::ostream &os;
indent_scope( std::ostream &inos ) : os( inos ) { os << indent; }
~indent_scope() { os << outdent; }
};
int main() {
new scoped_streambuf( std::cout );
std::cout << "hello\n";
{
indent_scope s( std::cout );
std::cout << "world" << std::endl;
}
std::cout << "!\n";
}
Я проверил, что scoped_streambuf
действительно удаляет себя, когда связанный поток уничтожается, но, очевидно, сам std::cout
никогда не уничтожается в GCC.
Повышение уровня iostream fu, whee!