为什么把一个函数的return值乘以零,它不会短路?

Why doesn't it short-circuit when you multiply the return value of a function by zero?

考虑如下函数:

unsigned int fact(unsigned int i) {
    if (i <= 1) { return 1; }
    return i * fact(i-1);
}

如果我要实例化一个新变量 unsigned int f 使得 f = 0 * fact(5),为什么它不 "short circuit"?

unsigned int fact(unsigned int i) {
    std::cout << "a";
    if (i <= 1) { return 1; }
    return i * fact(i-1);
}

int main() {
    unsigned int f = 0 * fact(5);
}

这里的输出是aaaaa。如果 f 只能为零,为什么它会调用函数,假设它知道 return 类型?它不是从左到右评估吗,请参阅 0 * (unsigned int) 并知道右值将是 0

短路评估对于 &&(逻辑 )、||(逻辑 是强制性的) 和 ? (三元运算符)。对于其余的运算符,这是一个(可选的)优化。

表达式 0 * fact(5)fact(5) 的求值一般不能被优化掉,因为你知道整个表达式的结果是 0 因为调用fact() 可能会引入副作用(例如,修改一些全局变量),所以必须调用它。

正如 中所说,如果可以证明没有副作用,一个好的编译器会优化对 fact(5) 的调用。

Does it not evaluate left to right, see 0 * (unsigned int) and know the rvalue will be 0?

它可以,而且如果标准要求它会这样做。

但事实并非如此。

短路根本不是乘法的事情。他们本可以让它成为一件事,但可以说它会让人感到困惑。

我们都习惯于 f() || g() 可能会跳过对 g() 的调用,但您真的希望 0 * g() 做同样的事情吗?特别是因为 0 只是 十亿 可能整数中的一个?这将是一个奇怪的特定功能。 (相比之下,true 是两个布尔值中的一个。)

这与副作用无关,因为 g() 的副作用会被 f() || g() 如果 f() returns true 跳过。就是这样。

实际上,编译器可以0 * g()中省略对g()的调用,如果它知道g()没有副作用的话(所以程序的行为不会改变),但这不是短路;那是 .