C++ 折叠表达式中的短路

C++ 折叠表达式中的短路,c++,c++17,lazy-evaluation,short-circuiting,fold-expression,C++,C++17,Lazy Evaluation,Short Circuiting,Fold Expression,这是一个自我触发的问题,基于我给出的自我回答 这似乎是一个非常令人信服的解释,解释了为什么在中可以使用逻辑运算符的短路,以及在函数中使用可变参数包装折叠表达式似乎是非短路的事实(事实上,答案解释说,是函数调用触发了对所有参数的求值,然后函数体内部才会发生短路) 然而,在我看来,以下代码证明(至少当折叠表达式中的参数为2时)不会发生短路: #包括 #包括 constexpr auto all_r=[](auto const&…ps){ 返回[&ps..](自动常量和x){ 回报率(ps(x)&…)

这是一个自我触发的问题,基于我给出的自我回答

这似乎是一个非常令人信服的解释,解释了为什么在中可以使用逻辑运算符的短路,以及在函数中使用可变参数包装折叠表达式似乎是非短路的事实(事实上,答案解释说,是函数调用触发了对所有参数的求值,然后函数体内部才会发生短路)

然而,在我看来,以下代码证明(至少当折叠表达式中的参数为2时)不会发生短路:

#包括
#包括
constexpr auto all_r=[](auto const&…ps){
返回[&ps..](自动常量和x){
回报率(ps(x)&…);
};
};
constexpr auto all_l=[](auto const&…ps){
返回[&ps..](自动常量和x){
回报率(…&&ps(x));
};
};
constexpr auto具有_值=[](标准::可选o){
返回o.具有_值();
};
constexpr auto具有_正=[](标准::可选o){
断言(o.has_value());
返回o.value()>0;
};
int main(){
断言(!(has_值(std::optional{})和&has_正值(std::optional{}));
//assert(!(has_positive(std::optional{})和&has_value(std::optional{}));//在运行时预期失败
assert(!all_r(has_value,has_positive)(std::optional{}));
assert(!all_l(has_value,has_positive)(std::optional{});//我希望它在运行时失败
//assert(!all_r(has_正值,has_值)(std::optional{}));
//assert(!all_l(has_-positive,has_-value)(std::optional{});//我希望这在运行时能够成功
}

Pack&&…
的含义开始

有一个相当可读的描述

Pack&…
变成
Pack1&&(Pack2&&(Pack3&&Pack4))
…&&包装
变为
((包装1和包装2)和包装3)和包装4

在计算
&&
时,我们在解析树的顶部从左到右进行计算

对于
Pack&&…
案例,此顶级
&&
Pack1
然后是and运算符,然后是
(Pack2&&(Pack3&&Pack4))
首先计算左侧,如果为false,则停止

对于
..&&Pack
案例,顶层
&
位于右侧。它的左手是
((Pack1&&Pack2)和&Pack3)
,右手是
Pack4

但是为了找出左手是否为真,我们继续应用这个规则。我们最后计算的第一个术语是…
Pack1
。如果它为假,我们就不去计算其余的

虽然树的形状不同,但它没有人们想象的那么重要

  +
 / \
A   +
   / \
  B   C

执行顺序遍历时,以相同的顺序访问节点,左/右折叠只需切换生成这两个表达式树中的哪一个

在某些情况下,左/右折叠很重要,但对事物求值为bool的
&
不在其中。

..&&ps(x)
带有四个谓词
a、b、c、d
扩展为

( ( a(x) && b(x) ) && c(x) ) && d(x)
a(x) && ( b(x) && ( c(x) && d(x) ) )
这导致了这种评估顺序:
a b c d

ps(x)&&&……
扩展到

( ( a(x) && b(x) ) && c(x) ) && d(x)
a(x) && ( b(x) && ( c(x) && d(x) ) )
这导致了相同的评估顺序:
a b c d


这不会改变任何关于短路的情况;一旦一个为假,评估就会停止。

我不认为
ps(x)&&&……
…&&&ps(x)
更改了
&&&
操作的关联性。那么,为什么期望不同的行为?@prog fh这两种形式正是在一个方向或另一个方向上施加关联性。但是,只有两个参数,这会发生什么变化?(从三个参数开始,我看到区别)我确实使用了一个不好的术语:不是关联性,而是求值顺序。@prog fh我想我已经理解了我的错误。我错误地期望求值顺序在这两种形式中被镜像,就像关联性被镜像一样。