One of the corners of C++20 constraints is that there are certain situations in which you have to write requires requires
. For instance, this example from [expr.prim.req]/3:
A requires-expression can also be used in a requires-clause ([temp]) as a way of writing ad hoc constraints on template arguments such as the one below:
template<typename T>
requires requires (T x) { x + x; }
T add(T a, T b) { return a + b; }
The first requires introduces the requires-clause, and the second introduces the requires-expression.
What is the technical reason behind needing that second requires
keyword? Why can't we just allow writing:
template<typename T>
requires (T x) { x + x; }
T add(T a, T b) { return a + b; }
(Note: please don't answer that the grammar requires
it)
It is because the grammar requires it. It does.
A requires
constraint does not have to use a requires
expression. It can use any more-or-less arbitrary boolean constant expression. Therefore, requires (foo)
must be a legitimate requires
constraint.
A requires
expression (that thing that tests whether certain things follow certain constraints) is a distinct construct; it's just introduced by the same keyword. requires (foo f)
would be the beginning of a valid requires
expression.
What you want is that if you use requires
in a place that accepts constraints, you should be able to make a "constraint+expression" out of the requires
clause.
So here's the question: if you put requires (foo)
into a place that is appropriate for a requires constraint... how far does the parser have to go before it can realize that this is a requires constraint rather than a constraint+expression the way you want it to be?
Consider this:
void bar() requires (foo)
{
//stuff
}
If foo
is a type, then (foo)
is a parameter list of a requires expression, and everything in the {}
is not the body of the function but the body of that requires
expression. Otherwise, foo
is an expression in a requires
clause.
Well, you could say that the compiler should just figure out what foo
is first. But C++ really doesn't like it when the basic act of parsing a sequence of tokens requires that the compiler figure out what those identifiers mean before it can make sense of the tokens. Yes, C++ is context-sensitive, so this does happen. But the committee prefers to avoid it where possible.
So yes, it's grammar.