【问题标题】:Cancelling std::cout code lines using preprocessor使用预处理器取消 std::cout 代码行
【发布时间】:2009-09-07 13:54:56
【问题描述】:

可以使用#define printf 删除对printf() 的所有调用。如果我有很多像 std::cout << x << endl; 这样的调试打印怎么办?如何使用预处理器快速关闭单个文件中的cout << 语句?

【问题讨论】:

    标签: c++ c-preprocessor cout


    【解决方案1】:

    正如“放松”已经说过的那样,快速解决方案是无所事事的流。不过有更好的实现:

    class NullStream {
        public:
        NullStream() { }
        template<typename T> NullStream& operator<<(T const&) { return *this; }
    };
    

    您仍然对std::cout 有一点问题,因为这是三个标记的序列,您真的不想单独重新定义stdcout。一个简单的解决方案是

    #ifdef NDEBUG
        #define COUT std::cout
    #else
        #define COUT NullStream()
    #endif
    
    COUT << "Hello, world" << std::endl;
    

    【讨论】:

      【解决方案2】:

      作为一般原则,应避免记录到标准输出 - 最好记录到日志文件,然后您可以使用标准配置工具更改日志级别,或完全关闭它。

      只要我的 0.02 美元.....

      【讨论】:

        【解决方案3】:

        用以下内容替换您的调试输出语句:

        IFDBG(cout << result << endl);
        

        然后你可以相应地定义宏:

        #ifdef DEBUG
        #  define IFDBG(x) x
        #else
        #  define IFDBG(x)
        #endif
        

        【讨论】:

        • 这看起来不适用于IFDBG(cout &lt;&lt; foo(x,y) &lt;&lt; std::endl);。逗号会破坏宏。
        • 不,这不会破坏宏,因为宏可以在括号内转义范围。但是这个调用会破坏它: IFDBG(cout ()
        【解决方案4】:

        如果您正在寻找可以快速删除调试语句的东西,NullStream 可能是一个很好的解决方案。不过,我建议您创建自己的调试类,当需要更多调试功能时,可以根据需要对其进行扩展:

        class MyDebug
        {
            std::ostream & stream;
          public:
            MyDebug(std::ostream & s) : stream(s) {}
        #ifdef NDEBUG
            template<typename T>
            MyDebug & operator<<(T& item)
            {
              stream << item;
              return *this;
            }
        #else
            template<typename T>
            MyDebug & operator<<(T&)
            {
              return *this;
            }
        #endif
        };
        

        这是一个简单的设置,可以做你最初想做的事情,而且它还有一个额外的好处,可以让你添加调试级别等功能。

        更新: 现在由于操纵器是作为函数实现的,如果你也想接受操纵器(endl),你可以添加:

        MyDebug & operator<<(std::ostream & (*pf)(std::ostream&))
        {
          stream << pf;
          return *this;
        }
        

        对于所有操纵器类型(这样您就不必为所有操纵器类型重载):

        template<typename R, typename P>
        MyDebug & operator<<(R & (*pf)(P &))
        {
          stream << pf;
          return *this;
        }
        

        小心最后一个,因为它也会接受常规函数指针。

        【讨论】:

        • 如果我将 endl 传递给这个流,它会给出错误.. 看起来 T& 项目不接受 endl.. 任何线索如何也为此重载它?
        • 非常感谢我很感激
        • 你好,operator
        【解决方案5】:

        定义这个宏:

        #ifdef DEBUG
            #define MY_LOG std::cout
        #else
            #define MY_LOG if(false) std::cout
        #endif
        

        这个宏的优势在于编译器优化

        如果放置在这些 IF 中的表达式在编译时是常量且可确定,那么您几乎可以肯定编译器已经为您从代码中删除了它们... https://stackoverflow.com/a/14657645/5052296

        【讨论】:

        • 对我来说这是最好的答案。最后我解决了这个问题!谢谢@y30!
        【解决方案6】:

        您可能可以使用一个名为cerr 的实例来定义一个新的类流类的预处理器hack,它什么都不做。如果你真的很幸运,编译器会看到该函数什么都不做,并优化对operator&lt;&lt;() 的调用。

        类似

        class NullStream
        {
        public:
          NullStream();
        
          NullStream& operator<<(const std::string& text) { return *this; }
          // And operators for other types, too
        }
        static NullStream cerr;
        

        不过,这确实是个 hack,最好是(远)浏览您的源代码并添加对日志记录的适当支持。

        【讨论】:

          【解决方案7】:

          定义一个替换 cout 的宏不是您应该上传到 VCS 的内容,但如果您只是在调试期间临时这样做,我认为它可以发挥作用。所以你可以把cout替换成ostream(0)就好了

          #ifdef NDEBUG
          #define cout ostream(0).flush()
          #endif
          

          这样,它可以与std::cout 和普通cout 一起使用,并且ostream 在包含&lt;iostream&gt; 时可用。写入ostream(0) 是无操作的。 flush 函数调用已完成,以便您获得对它的非常量引用(因此它还绑定到用于输出 std::string 和其他的非成员 operator&lt;&lt;)。因为它的类型是ostream,它的行为应该和cout完全一样。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2018-01-03
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多