折叠表达式中的短路

问题描述

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

This 似乎非常有说服力地解释了为什么在 fold expressions 中可以使用逻辑运算符的短路,以及将折叠表达式包装在具有可变参数的函数中的事实 似乎 是非短路的(实际上,答案解释说,在函数体内发生短路之前,函数调用会触发对所有参数的评估)。

但是,在我看来,以下代码证明(至少当折叠表达式中的参数为 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) 带有四个谓词 a,b,c,d 扩展为

( ( a(x) && b(x) ) && c(x) ) && d(x)

导致此评估顺序:a b c d

ps(x) && ... 扩展为

a(x) && ( b(x) && ( c(x) && d(x) ) )

导致相同的求值顺序:a b c d

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

,

Pack && ... 的含义开始。

Cppreference 有一个非常易读的描述。

Pack && ... 变成 Pack1 && (Pack2 && (Pack3 && Pack4))) ... && Pack 变成 (((Pack1 && Pack2) && Pack3) && Pack4

在评估 && 时,我们在分析树的顶部从左到右评估。

对于 Pack&&... 情况,此顶级 &&Pack1,然后是 and 运算符,然后是 (Pack2 && (Pack3 && Pack4))&& 首先评估左侧,如果为 false 则停止。

对于 ...&&Pack 情况,顶级 && 位于右侧。它的左手是(((Pack1 && Pack2) && Pack3),右手是Pack4

但是为了确定左手是否正确,我们继续应用该规则。我们最终评估的第一个术语是... Pack1。如果它是假的,我们就不用去评估其余的了。

虽然树的形状不同,但它并不像人们想象的那么重要。

  +
 / \
A   +
   / \
  B   C

      +
     / \
    +   C
   / \
  A   B

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

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

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...