在C++中,短路`operator<<`输出是什么意思?

4

我有一些代码,其中散布着这样的结构:

if(debug) {
    Output << "f1: " << f1() << "\n";
}

现在我想要做的是编写一个流类Debug,我可以像这样编写它:

Debug << "f1: " << f1() << "\n";

如果设置了某个全局标志,则会生成输出,否则不会。现在可以通过使Debug返回一个流并将其发送到/dev/null来轻松完成此操作,这将吞噬输出。问题是f1()仍然会被评估(并且被呈现为可能更昂贵的文本表示),这可能对性能非常不利。现在我的问题是:有没有任何技巧可以跳过对f1()的“评估”?
"f1: " << f1() << "\n"

如果Debug决定不输出任何内容,那么是否可以完全禁用输出?这与C++对于f() && g()的短路操作类似,如果f()false,则g()不会被执行。(我曾经考虑编写一个使用&&作为输出运算符的流类,但据我所读,重载的operator&&不能进行短路操作。)

今天早些时候的这个相关问题可能有解决方案。 - juanchopanza
@juanchopanza:这些问题仍然(可能)评估参数。我认为,除非您将格式切换为类似于“DEBUGOUT(“f1:“<< f1()<<“\ n”);”这样的内容,否则无法按要求完成。 - Mooing Duck
@MooingDuck 是正确的。他们只是避免了流式传输。 - juanchopanza
这个SO看起来很相似:https://dev59.com/mm445IYBdhLWcg3wGmg6 - marcinj
@MooingDuck:除了使用邪恶宏的那个。 - Mike Seymour
3个回答

5

您可以定义此宏:

#define Debug_Stream \
if(!debug); else Output

这将使得这个变成:
Debug_Stream << "f1: " << f1() << "\n";

变成等价于这个:

if(debug) {
    Output << "f1: " << f1() << "\n";
}

但字面上(加上空格以便阅读)

if(!debug);
else
    Output << "f1: " << f1() << "\n";

2
这将容易出现悬挂else不匹配的问题。 - Mark B
1
@MarkB:可以通过定义 if(!debug);else Output 来解决。 - Yakov Galka
很好的发现,马克。感谢 @ybungalobill 的建议。我已经修改了答案来修复问题。 - Eric Finn

4

如果您不排斥使用宏,并愿意接受以下语法:

Debug( "f1: " << f() << '\n' );

很简单:只需定义类似以下内容的东西:

。它与HTML标记相同。
#define Debug( x ) debug != NULL && *debug << x;

这种方法有一定的危险性,因为你不能像平常一样用括号把参数括起来作为一个整体。(另一方面,我也见过它在很多应用中被使用,并没有出现问题。)宏方法的额外优点是,如果需要,可以自动插入__FILE____LINE__。或者通过定义宏为空来有条件地完全禁止所有代码。


2
我认为您可以通过创建一个延迟求值器来实现此功能,该求值器包装昂贵的函数调用。您的流应该知道需要调用所引用的函数的延迟求值器类型,但除此之外,它不会执行任何操作,从而避免了昂贵的调用。无调试流知道对于代理求值器对象,只需完全跳过评估即可。
例如,调用可能如下所示:
Debug << "123" << delay(f()) << "456" << std::endl;

这确实涉及到在调试行中调用延迟。它避免了可能是关键问题的宏的需求。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接