Lambdas in unevaluated context (requires expressions)

Viewed 155

I know there are several questions about this topic but hear me out, please.

I'm aware that we can use capture-less lambdas in unevaluated contexts (like decltype), but what about lambdas that do capture?

I couldn't find anything in the current C++ standard that would suggest that this is at all a problem since C++20, but I'm by no means a language lawyer.

What I see though, is that the major compilers differ in their results.

Are these concepts valid?

template <typename T>
concept C1 = requires { []{}; };

template <typename T>
concept C2 = requires(T t) { [&t]{}; };
1 Answers

I'm aware that we can use capture-less lambdas in unevaluated contexts

This is not restricted to stateless lambdas. P0315R4 (Wording for lambdas in unevaluated contexts) removed the restrictions for lambdas (not just stateless ones) to not appear in unevaluated lambdas, whilst modifying the wording for some sections relating to the original intent for the restriction:

The core language changes introduced in this paper are a bit tricky. The reason is that we remove many restrictions on lambda expressions, yet we still want to keep closure types out of the signature of external functions, which would be a nightmare for implementations.

The paper introduces no particular constraints on lambdas w.r.t. concepts, and we may simply turn to [temp.concept]/6 to govern this case:

The constraint-expression of a concept-definition is an unevaluated operand ([expr.context]).

As there is no longer any general restriction on lambas (stateless or not) to not appear as the operand in unevaluated contexts, and there is moreover no explicit restriction in the context of concepts, both concepts C1 and C2 are well-formed.

And indeed, as compared to the restriction on closure types in some declarations, concepts are not instantiated, as per [temp.concept]/5, and does fall under the ODR-considerations that are considered "a bit tricky" in P0315R4.

Related