Search code examples
c++language-lawyerc++20c++-conceptsrequires-clause

Does the `requires` nested in a requires-expression introduce a requires-clause?


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

And a constraint-expression is a logical-expression too.

But what I don't understand is where the parenthesis are gone.


Solution

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