From questions like this, from C++20 - The Complete Guide, and even from cppreference, my understanding is that the keyword requires
can do one of 2 things only:
and I also think I've understand more or less what they are for, thanks to linked sources.
However, I'm puzzled by the use of requires
inside a requires-expression, e.g.
template<typename T>
… requires {
requires std::is_const_v<T>;
}
From the standard draft, I read that a requires-expression (e.g. the one introduced by the first requires
in the snippet above) must have a requirement-body, which must in turn be a { requirement-seq }
, i.e. something between curly braces, which is not the case of std::is_const_v<T>;
, from which I deduce that requires std::is_const_v<T>;
is a requires-clause, that should look like this
requires
constraint-logical-or-expression
However, [expr.prim.req.nested] tells me that a nested-requirement looks like this:
requires
constraint-expression;
So maybe use of requires
nested in a requires-expression is not a requires-clause?
If it is, I think the difference between the two quoted grammars above should mean that nested-requirements are a subset of requires-clauses, in which case I should be able to see, following the various cross-references, that a constraint-expression is a constraint-logical-or-expression but not viceversa. Now I see that
( expression )
And a constraint-expression is a logical-expression too.
But what I don't understand is where the parenthesis are gone.
A requires-clause is a grammatical construct that is only introduced by a declarator (only for templated functions), function definition, class member declarator, template header, or lambda syntax. You can see that from the grammar.
The only way to put a requires-clause inside a requires-expression is to smuggle it in via a lambda. But then, the clause applies just to that lambda.
A nested-requirement is not a requires-clause, neither grammatically nor semantically. The key difference is that a requires-clause is required to only be a series of primary expressions merged by &&
and ||
. This is important for being able to decompose a requires-clause down into a series of atomic constraints. Nested-requirements are able to do more because a nested requirement is itself a single atomic constraint.
Put more simply, the requires-clause defines a constraint:
A constraint is a sequence of logical operations and operands that specifies requirements on template arguments.
A nested-requirement is itself an atomic constraint.