C/C++优化器是否可以决定延迟评估仅用于短路评估的值



我喜欢重构像这样的复杂条件:

if (foo(blah) || (bar(param1, param2, param3) && !obj.longMethodName())) ...

进入这个:

bool foo_true = foo(blah);
bool bar_true = bar(param1, param2, param3);
bool long_true = obj.longMethodName();
if (foo_true || (bar_true && !long_true)) ...

我认为这使代码更容易理解,并且有助于调试,因为您可以看到用于计算最终条件的中间结果。

但是:在原始代码中,由于短路,只有当foo返回true时,才会评估bar,而只有当bar返回true时,才会对longMethodName进行评估。

假设函数是"纯"的,方法是const,编译器可以看到所有东西的函数体是否允许C++优化器推迟评估我的中间值,直到需要它们为止

当然。只要编译器能够看到足够的信息来确定foobarobj.longMethodName()没有对代码的可观察行为的其他影响。

是否有编译器这样做是另一个问题。我很怀疑它它需要一些非常特殊的逻辑,而这些逻辑不在优化技术的常用列表实际上没有人这样做。(我怀疑大多数程序员会找到格式正确的原始版本比有很多额外变量的更可读。)

编辑:

我想知道是否值得指出编译器是允许的调用所有三个函数,即使if已写入:

if ( foo( blah ) || (bar( p1, p2, p3 ) && ! obj.lMN() ) )

(尽管我无法想象会有这样的标准。)没有关于何时调用哪些函数的要求;它只要求可观察的行为是相同的价值观和顺序相同——没有关于时间)"好像"遵循了程序的形式语义。唯一可观察到的行为是IO(以某种形式)和对易失性对象的访问。

否。编译器不允许进行优化,因为它无法确定你是指短路,还是想在评估bar时产生潜在的副作用。

否。C++没有一个没有副作用的纯方法的概念,所以真的没有优化的方法。

这里的问题是foobar可以在另一个编译单元中实现,而C++没有函数纯度的概念。这意味着foobar可能会产生副作用(屏幕或全局变量的变化),因此必须进行评估才能获得预期行为。

有趣的是,使用GCC,函数可以用pure属性声明。这告诉编译器该函数没有任何副作用。因此可以称之为懒惰。请参阅此处了解更多详细信息。

我不确定赋值是否已经被视为副作用。至少可以说,很难确定移动实际呼叫是否安全。

但是,我想指出的是,在c++11中,可以使用与OP在使用std::bind的示例中使用的语法几乎完全相同的语法来实现OP所追求的目标。

只是foo_true不会被定义为

bool foo_true = foo(blah);

而是

CCD_ 20。

然后可以将CCD_ 21检查为CCD_。

它是否干净,取决于个人的事情IMO。但我相信它的行为符合双方的意愿和期望。完整代码:

#include <iostream>
#include <functional>
using namespace std;
bool foo(int blah){
cout << "blah: " << blah << 'n';
return blah;
}
bool bar(bool negate_me){
cout << "negate_me: " << negate_me << 'n';
return !negate_me;
}
int main() {
bool test = true;
int param = 42;
auto foo_true = std::bind(foo, test);
auto bar_true = std::bind(bar, param);
if (foo_true() || bar_true() ) cout << "TESTn";
return 0;
}

输出:

blah: 1
TEST

未调用bar。将test更改为false,它将是

最新更新