[英]Short circuiting in fold expressions
This is a self triggered question based on a self-answer I gave here .这是一个基于我在此处给出的自我回答的自我触发问题。
This seems a pretty convincing explanation of why short-circuiting of logical operators is available in fold expressions , and of the fact that wrapping a fold expression in a function with a variadic argument seems to be non short-circuting (in fact, the answer explains, it's the function call which triggers the evaluation of all arguments, before the short-circuit can take place inside the function body).这似乎是一个非常令人信服的解释,解释了为什么折叠表达式中可以使用逻辑运算符的短路,并且使用可变参数将折叠表达式包装在 function 中似乎是非短路的(事实上,答案解释了,是 function 调用触发了对所有 arguments 的评估,在 function 主体内部发生短路之前)。
However, the following code seems to me, proves that (at least when the arguments in a fold expression are 2) the short-circuiting doesn't happen:但是,在我看来,以下代码证明(至少当折叠表达式中的 arguments 为 2 时)不会发生短路:
#include <assert.h>
#include <optional>
constexpr auto all_r = [](auto const& ... ps){
return [&ps...](auto const& x){
return (ps(x) && ...);
};
};
constexpr auto all_l = [](auto const& ... ps){
return [&ps...](auto const& x){
return (... && ps(x));
};
};
constexpr auto has_value = [](std::optional<int> o){
return o.has_value();
};
constexpr auto has_positive = [](std::optional<int> o){
assert(o.has_value());
return o.value() > 0;
};
int main() {
assert(!(has_value(std::optional<int>{}) && has_positive(std::optional<int>{})));
//assert(!(has_positive(std::optional<int>{}) && has_value(std::optional<int>{}))); // expectedly fails at run-time
assert(!all_r(has_value, has_positive)(std::optional<int>{}));
assert(!all_l(has_value, has_positive)(std::optional<int>{})); // I expected this to fail at run-time
//assert(!all_r(has_positive, has_value)(std::optional<int>{}));
//assert(!all_l(has_positive, has_value)(std::optional<int>{})); // I expected this to succeed at run-time
}
... && ps(x)
with four predicates a, b, c, d
expands to ... && ps(x)
有四个谓词a, b, c, d
展开为
( ( a(x) && b(x) ) && c(x) ) && d(x)
which leads to this order of evaluation: ab c d
这导致了这个评估顺序:
ab c d
ps(x) &&...
expands to ps(x) &&...
展开为
a(x) && ( b(x) && ( c(x) && d(x) ) )
which leads to the same order of evaluation: ab c d
这导致相同的评估顺序:
ab c d
This does not change anything about short-circuiting;这不会改变任何关于短路的事情。 as soon as one is false, the evaluation stops.
一旦一个是假的,评估就会停止。
Start with what Pack &&...
means.从
Pack &&...
的含义开始。
Cppreference has a pretty readable description. Cppreference有一个非常易读的描述。
Pack &&...
becomes Pack1 && (Pack2 && (Pack3 && Pack4)))
... && Pack
becomes (((Pack1 && Pack2) && Pack3) && Pack4
Pack &&...
变成Pack1 && (Pack2 && (Pack3 && Pack4)))
... && Pack
变成(((Pack1 && Pack2) && Pack3) && Pack4
When evaluating &&
we evaluate left to right at the top of the parse tree.在评估
&&
时,我们在解析树的顶部从左到右评估。
For the Pack&&...
case, this top level &&
is Pack1
then the and operator, then (Pack2 && (Pack3 && Pack4))
.对于
Pack&&...
情况,这个顶级&&
是Pack1
然后是 and 运算符,然后是(Pack2 && (Pack3 && Pack4))
。 &&
evaluates the left side first, and if false it stops. &&
首先评估左侧,如果为假则停止。
For the ...&&Pack
case, the top level &&
is way on the right.对于
...&&Pack
案例,顶层&&
位于右侧。 Its left hand is (((Pack1 && Pack2) && Pack3)
and its right hand is Pack4
.它的左手是
(((Pack1 && Pack2) && Pack3)
,右手是Pack4
。
But to find out if the left hand is true, we keep on applying that rule.但是要确定左手是否为真,我们继续应用该规则。 And the very first term we end up evaluating is...
Pack1
.我们最终评估的第一个术语是...
Pack1
。 Which if it is false, we don't bother evaluating the rest.如果它是假的,我们不会费心评估 rest。
While the shape of the tree is different, it doesn't matter as much as one might think.虽然树的形状不同,但它并不像人们想象的那么重要。
+
/ \
A +
/ \
B C
and和
+
/ \
+ C
/ \
A B
when doing an in order traversal visit the nodes in the same order, and left / right fold just switch which of these two expression trees is generated.在进行顺序遍历时,以相同的顺序访问节点,左/右折叠只需切换生成这两个表达式树中的哪一个。
There are cases where the left/right fold matters, but &&
on things evaluating to bool
isn't one of them.在某些情况下,左/右折叠很重要,但
&&
在评估为bool
的事物上不是其中之一。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.