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

575 Views Asked by At

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.

2

There are 2 best solutions below

3
Nicol Bolas On BEST ANSWER

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.

0
courage On

The C++ standard never says requires can only be the beginning of requires-clause and requires-expression. It can also be the beginning of nested-requirement, which is one of the four types of requirements in the requirement body for requires-expression.

Althrough nested-requirement may looks like requires-clause in grammar, they are not the same. For example:

template <typename T>
concept CF = false;

template <typename T>
void foo()
    requires // requires clause
    requires // requires expression
{
    requires !CF<T>; // nested requirement
}
{}

template <typename T>
void bar()
    requires !CF<T> // invalid requires clause
{}

I'm not sure whether the keyword page for requires on cppreference is correct (maybe incomplete?). requires-clause and nested-requirement are totally different things. I think it's OK to say requires can be the beginning of 3 things. If you want to find all the usages for a keyword, I think the best way is to read the Index page of the C++ standard.