Search code examples
c++c++17lazy-evaluationshort-circuitingfold-expression

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).

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:

#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
}

Solution

  • ... && ps(x) with four predicates a, b, c, d expands to

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

    which leads to this order of evaluation: a b c d

    ps(x) && ... expands to

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

    which leads to the same order of evaluation: a b c d

    This does not change anything about short-circuiting; as soon as one is false, the evaluation stops.