Not so long ago requires-expressions (the phrase introduced by the second requires) was not allowed in constraint-expressions (the phrase introduced by the first requires). It could only appear in concept definitions. In fact, this is exactly what is proposed in the section of that paper where that claim appears.
However, in 2016, there was a proposal to relax that restriction [Editor's note: P0266]. Note the strikethrough of paragraph 4 in section 4 of the paper. And thus was born requires requires.
To tell the truth, I had never actually implemented that restriction in GCC, so it had always been possible. I think that Walter may have discovered that and found it useful, leading to that paper.
Lest anybody think that I wasn't sensitive to writing requires twice, I did spend some time trying to determine if that could be simplified. Short answer: no.
The problem is that there are two grammatical constructs that need to introduced after a template parameter list: very commonly a constraint expression (like P && Q
) and occasionally syntactic requirements (like requires (T a) { ... }
). That's called a requires-expression.
The first requires introduces the constraint. The second requires introduces the requires-expression. That's just the way the grammar composes. I don't find it confusing at all.
I tried, at one point, to collapse these to a single requires. Unfortunately, that leads to some seriously difficult parsing problems. You can't easily tell, for example if a (
after the requires denotes a nested subexpression or a parameter-list. I don't believe that there is a perfect disambiguation of those syntaxes (see the rationale for uniform initialization syntax; this problem is there too).
So you make a choice: make requires introduce an expression (as it does now) or make it introduce a parameterized list of requirements.
I chose the current approach because most of the time (as in nearly 100% of the time), I want something other than a requires-expression. And in the exceedingly rare case I did want a requires-expression for ad hoc constraints, I really don't mind writing the word twice. It's a an obvious indicator that I haven't developed a sufficiently sound abstraction for the template. (Because if I had, it would have a name.)
I could have chosen to make the requires introduce a requires-expression. That's actually worse, because practically all of your constraints would start to look like this:
template<typename T>
requires { requires Eq<T>; }
void f(T a, T b);
Here, the 2nd requires is called a nested-requirement; it evaluates its expression (other code in the block of the requires-expression is not evaluated). I think this is way worse than the status quo. Now, you get to write requires twice everywhere.
I could also have used more keywords. This is a problem in its own right---and it's not just bike shedding. There might be a way to "redistribute" keywords to avoid the duplication, but I haven't given that serious thought. But that doesn't really change the essence of the problem.
noexcept
会存在歧义。noexcept(f())
的含义可能是,如果f()
的结果为真或者f()
是noexcept
的话,则表示该函数是noexcept
的。 - Passer Byrequires
子句可以有任何 constexpr 谓词,对吧? - StoryTeller - Unslander Monica