5

To avoid recursive template programming I am relying on the short circuit evaluation of the result of lambdas combined with logical && using a fold expression. Is that safe to do or will the compiler optimize away the expression because it is not used even if it has side effects?

For example consider the following code:

#include <cassert>
#include <utility>

template <typename... Ts> 
int count_leading_good(Ts &&...ts) {
  int N{0};
  ([&](auto &&t) -> bool {
    if (t.good) {
      N += 1;
      return true;
    }
    return false;
  }(std::forward<Ts>(ts)) && ...);
  return N;
}
struct A {
  bool good{true};
};

struct B {
  bool good{false};
};

int main(int argc, char *argv[]) {
  assert(count_leading_good(A{}, A{}, A{}, B{}, A{}) == 3);
}

Is it guaranteed that the assert never fails, i.e. that the fold expression will never be optimized away for any compilation flags?
Is there some C++ rule that ensures this?
Note that the result of the logical && is not used.

3
  • 2
    I added the language-lawyer tag because this seems like a fit to have an answer quote the standard. Commented Oct 10 at 16:59
  • 3
    A binary fold expression is in the end just expanding to a sequence of && operations. So short circuiting applies. Which means N+1 will not be called after an expression has evaluated to false. expr.prim.fold and expr.log.and Commented Oct 10 at 17:20
  • 3
    the compiler can't optimize away code that has a visible side effect. Your code has a visible side effect (N changes), so you are only relying on the fact that && will short circuit and that has been asked and answered on SO before. Commented Oct 10 at 17:24

1 Answer 1

5

Removal of code producing unused result:

In general the compiler is not allowed to discard code that produces a side effect (like the calls to the lambda that change N) due to the as-if rule.
You can see quotes from the standard here: What exactly is the "as-if" rule?.

Regarding fold-expression and short-circuiting:

fold expressions are only a mechanism for us programmers to express some logic in a generic way.

But when the compiler instantiates the template they "disappear" in a way and replaced with the actual templated types etc.

For example in your case the compiler will instantiate count_leading_good to something like:

int count_leading_good_12345___(A && t1, A && t2, A && t3, B && t4,A && t5) {
   int N{0};
   auto lambda = [&](auto &&t) -> bool { ... }
   lambda(t1) && lambda(t2) && lambda(t3) && lambda(t4) && lambda(t5);
   return N;
}

As you can see the fold expression is "unfolded" based on the concrete types.

Therefore the usual rules of short-circuiting apply.

So the bottom line is that the lambda will not be optimized out, and invoked up until the call with t4 returning false and the assert will not fail.

Since the language-lawyer tag was added, here are the relevant articles from the standard, as already mentioned by @PepijnKramer:

  1. Fold-expressions: [expr.prim.fold].
  2. Logical AND operator: [expr.log.and].
Sign up to request clarification or add additional context in comments.

4 Comments

Can you please also add a relevant article from the standard about @NathanOliver's comment. My concern with this code was that an unused result of a logical operation would not guarantee the side effects.
Not sure I understand. Once you see the unfolding, isn't it clear that the expression will short-circuit ? the fact that sub expressions that are not executed due to short circuit have potential side effect does not matter: they will be short-circuited and not executed. Thats' the essence of short-circuiting. This is also mentioned here.
No I understand the short-circuiting fine but I somehow thought that the compiler might remove the whole logical and expression if the result not used. But now I realized it is not allowed by the as-if rule, that was the rule I was missing. Thank you.
@phinz I editted to clarify.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.