C ++中的高级选项卡位置?

时间:2010-09-07 16:28:39

标签: c++ formatting

我正在编写一个程序,它的调试输出遍布整个程序。这一切都很好,但我希望能够提升不同范围内事物的标签位置,例如,这就是我现在所拥有的:

#ifndef NDEBUG
printf("Updating player\n");
#endif
player.Update();
#ifndef NDEBUG
printf("Done updating player\n");
#endif

我希望这两个块之间调用的所有输出都被一个选项卡位置提前;但是,只需在Player :: Update()输出的开头添加选项卡就非常笨重且难以维护。

有人帮忙吗? (注意:我使用cout没有问题;我最近刚刚讲了cout的开销和不安全感)

3 个答案:

答案 0 :(得分:6)

不是直接使用printf,而是创建一个类来处理控制台输出,并且有一个成员函数,例如SetTabLevel() - 也许还有IncrementTabLevel()DecrementTabLevel() - 它告诉班级在每个后续行的开头添加多少个选项卡。

答案 1 :(得分:3)

你可以拥有一个基本上保持“标签计数”且具有print_line功能的类:调用时,它会输出制表符计数选项卡,然后打印该行。虽然你可以有一个increment_indent函数,你可以使用RAII创建一个姐妹对象TabIndent:当它被创建时,递增标签,当它被破坏时,减少缩进:

some_function()
{
    TabIndent ti(global_debug_outputter);

    global_debug_outputted.print_line("foo bar baz");
    // ti's d-tor calls global_debug_outputted.unindent()
}

class TabIndent
{
public:
    TabIndent(Outputter &o) : m_outputter(o)
    {
        o.indent();
    }
    ~TabIndent()
    {
        o.unindent();
    }
};

class Outputter
{
// functions indent, unindent, print_line...
};

好好使用inline s会让编译器在它们的主体为空时优化它们。在#ifndef类中使用Outputter,让编译器优化其余部分。

答案 2 :(得分:1)

好消息是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确实在关联的流被销毁时删除了自己,但显然{G}}本身在GCC上永远不会被销毁。

升级iostream fu,哇!