Is the expression b<[]{ return true; }()>
within the requires-clause in accordance with the C++20 standard? For some reason GCC rejects it and deems it to be an expression error, while MSVC and Clang accept it.
template<bool B>
inline constexpr bool b = B;
static_assert(requires { b<[]{ return true; }()>; });
GCC's error message:
<source>:3:15: error: static assertion failed
3 | static_assert(requires { b<[]{ return true; }()>; });
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<source>:3:15: note: constraints not satisfied
<source>:3:26: note: the required expression 'b<<expression error> >' is invalid,
because
3 | static_assert(requires { b<[]{ return true; }()>; });
| ^~~~~~~~~~~~~~~~~~~~~~~
This is a confirmed GCC bug. A requires-expression is a valid expression for a static assertion. The standard is wild in how deep the grammar goes, but here we go.
Per the grammar:
The only question after that is whether (per [decl.pre]) your provided requires clause satisfies the following:
[the expression] E is contextually converted to bool and the converted expression shall be a constant expression
Well, a requires-expression is definitely convertible to a boolean, per [exp.prim.req.general]
A requires-expression is a prvalue of type bool [...]
Your requires-expression is a simple-requirement that just requires an expression that may or may not depend on template substitution. In your case, there is no template substitution, so all that's needed for the requires
to pass is a valid expression, any valid expression. Your lambda is quite valid (and constexpr
). Note, however, that a lambda returning false
should be equally valid and cause static assertion to pass also:
static_assert(requires { b<([](){ return false; }())>; }); // pass
Therefore it's probably not a good idea to use a requires expression without template substitution.
A funny thing is that a static_assert
may also have a noexcept
expression, and wrapping your requires clause in one makes GCC 13.2 pass:
static_assert(noexcept(requires { b<([]{ return true; }())>; }));