【问题标题】:C++ - Passing std::ostream to a functionC++ - 将 std::ostream 传递给函数
【发布时间】:2010-02-03 11:50:45
【问题描述】:

我想到了一个 C++ 中的小调试内联函数:

void inline debug( int debug_level, ostream& out ) {
    if ( debug_level <= verbosity ) {
        out.flush();
    }
    else {
        ostream tmp;
        tmp << out;
    }
}

这是我想如何使用它的示例:

_debug( 7, cout << "Something something" << someint << endl );

但是它不能按我计划的方式工作 - 我希望它仅在详细级别高于或等于传递给函数的调试级别时打印消息,但无论调试级别如何,它似乎每次都会打印,因此数据保留在 cout 缓冲区中。到目前为止,我认为这个函数不是我最近想到的最好的主意,但我仍然想知道是否有办法清除与 cout、cerr 等相关的缓冲区。是否有可能让这种函数正常工作?

【问题讨论】:

  • 如果你想走Konrad的路线,使用空流的思想,看看这个问题stackoverflow.com/questions/760301/…
  • 哦,我只是不喜欢 oldschool-C 宏,我更喜欢 C++ 方式;)
  • 宏在 C++ 中的可避免性与在 C 中差不多。
  • 是的,明智地使用宏,但是对于日志记录,它们也可以很好地记录函数/文件/行号。不管你喜不喜欢,他们仍然有自己的位置。

标签: c++ iostream ostream


【解决方案1】:

使用如上所示的宏,或者像这样:

struct nullstream : ostream {
    nullstream() : ostream(0) { }
};

ostream& dout(int debug_level, ostream& out = cerr) {
    static nullstream dummy;
    return debug_level <= verbosity ? dummy : out;
}

// …

dout(level) << "foo" << endl;
dout(level, cout) << "IMPORTANT" << endl;

(使用endl也会触发flush,无需手动flush!)

【讨论】:

  • 唯一的麻烦是不必要的流缓冲区构造。最好避免流缓冲区构造;考虑到日志记录可能是您比无头进程中的任何其他操作更频繁地执行的操作。
  • @CodeMedic:这就是为什么流是static:在所有程序中,它只被构造一次。这几乎没有开销,您可以随意调用此方法。
  • @Konrad Rudolph:看起来很酷,但是不断写入 dummy 不会导致某种缓冲区溢出吗?
  • 这实际上导致了分段错误 - 我不得不使用 ofstream 并将其重定向到 /dev/null
  • 我在我的代码中使用了相同的技术;但是,它不会像上面显示的那样工作,因为(唯一的)ostream 构造函数需要一个 streambuf* 参数。因此,我通常会在构造返回的 ostream 对象时使用 struct nullbuf : streambuf {}; static nullbuf buf; 然后传递 &buf。
【解决方案2】:

我不确定是否可以使用函数/模板来完成。 我知道带有宏的代码(您的日志消息和流是分开的):

#define LOG(svrty, out, msg)\
do {\
  if (svrty >= debug_level) out << msg;\
} while(0)

虽然这可行,但我对更好的解决方案很感兴趣。 请注意,您应该让配置和调试级别决定登录到哪里。

【讨论】:

    【解决方案3】:

    它总是会打印消息,因为函数参数是在输入函数体之前评估的。您可以使用宏获得我认为您想要的效果,因为宏参数仅在使用时才被评估:

    #define DOUT( level, expr )   \
       if ( level >= verbosity )  {     \
          expr << endl;          \
      }
    

    使用中:

     DOUT( 42, cout << "The value is " << something );
    

    如果你很挑剔,你会想把它包装在一个 do/while 循环中——就我个人而言,我从不费心这样做。

    【讨论】:

    • @Neil:好吧,你真的应该打扰,因为现在你的用法是错误的:你在它后面放了一个多余的分号。不要想如果这是在 if 中,下一个语句是 else 会发生什么。
    • @Konrad 令人惊讶的是,我确实知道这一点。将其视为我的小编码弱点之一。
    【解决方案4】:

    调试级别运行时是否可配置?
    如果不是,您可以使用模板和模板专业化:

    template <int DebugLevel, int Verbosity>
    ostream &debug(ostream &out);
    
    template<>
    ostream &debug<7, 5>(ostream &out) { /* do stuff */ }
    

    这样,如果您不想输出任何内容,只需像 Konrad Rudolph 建议的那样返回虚拟 ostream。

    【讨论】:

      猜你喜欢
      • 2011-07-14
      • 1970-01-01
      • 1970-01-01
      • 2012-08-13
      • 2015-09-03
      • 2013-01-16
      • 1970-01-01
      • 1970-01-01
      • 2011-07-27
      相关资源
      最近更新 更多