215

One of the corners of C++20 concepts 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)

user3840170
  • 26,597
  • 4
  • 30
  • 62
Barry
  • 286,269
  • 29
  • 621
  • 977
  • Seems `requires` might be used for method of template class, and it would be "ambiguous" `template struct S {void f(T t) requires requires (T x) {x + x;} { t + t;} };` – Jarod42 Jan 15 '19 at 14:40
  • 33
    Suggestion: "Is there anything that requires requires requires?". More seriously, I have a hunch that it's the same reason behind `noexcept(noexcept(...))`. – Quentin Jan 15 '19 at 14:41
  • They say "_The first requires introduces the requires-clause, and the second introduces the requires-expression._", but this is not compatible with the grammar they give just above – bruno Jan 15 '19 at 14:42
  • 3
    @Quentin With `noexcept` there is ambiguity. `noexcept(f())` might mean to be `noexcept` if `f()` evaluates to true or if `f()` is `noexcept`. – Passer By Jan 15 '19 at 14:52
  • @PasserBy - Well, then isn't that the same reason here? A `requires` clause can have any constexpr predicate, no? – StoryTeller - Unslander Monica Jan 15 '19 at 14:55
  • One reason I can see for doing this is to make the parsing easier. When the compiler sees `requires` it knows the next symbol is the requirement, so we need the additional `requires` to tell it it needs to parse that requirement as an ad-hoc requirement. – NathanOliver Jan 15 '19 at 14:56
  • 15
    The two `requires` are homonyms in my opinion: they look the same, spell the same, smell the same, but are intrinsically different. If I were to suggest a fix, I'd suggest to rename one of them. – YSC Jan 15 '19 at 14:59
  • @StoryTeller Apparently yes, as demonstrated by NicolBolas, although to a lesser extent. – Passer By Jan 15 '19 at 15:09
  • It does make sense gramatically, weirdly enough. `add()` requires a `T` that in turn requires the ability to be added to other `T`s. So, while it looks repetitive, it makes sense if you think about it enough. (Where "I must be addable" is the expression, and "the function needs something that must be addable" is the constraint.) – Justin Time - Reinstate Monica Jan 15 '19 at 19:19

5 Answers5

114

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.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
  • 2
    Does it make sense to have a parameter list with a type but without a name? – NathanOliver Jan 15 '19 at 15:13
  • This reminds me of an [answer](https://stackoverflow.com/questions/38462104/getting-the-type-of-a-typename-or-expression/38462523#38462523) I wrote where, as far as I can tell, the compiler cannot make sense of the code before determining what `x` is. Another example is ADL working with function templates *only if* there's a similar function template in scope ([demo](http://coliru.stacked-crooked.com/a/cac6f5be4b684b1b)), otherwise parsing fails. I am under the impression that heavy context dependence is pretty common in C++. – Quentin Jan 15 '19 at 15:13
  • 3
    @Quentin: There are certainly cases of context-dependency in the C++ grammar. But the committee really does try to minimize that, and they definitely don't like adding *more*. – Nicol Bolas Jan 15 '19 at 15:25
  • If context is the reason, then using the same word in two contexts, is contrary to the intention. – Robert Andrzejuk Jan 15 '19 at 17:34
  • 1
    @RobertAndrzejuk: The use of `if` vs. `if constexpr` is not context-sensitive because telling one from the other is easily done based on the sequence of tokens. To the token sequence, an identifier is just an identifier. If the nature of that identifier determines how to parse the sequence of tokens, then you're dealing with something that is problematic in the parser. Not *impossible*, just "context sensitive". Using a keyword like this is not context sensitive in this regard because the location where you use those keywords defines the context. – Nicol Bolas Jan 15 '19 at 17:40
  • 3
    @RobertAndrzejuk: If `requires` appears after a `<>` set of template arguments or after a function parameter list, then it's a requires-clause. If `requires` appears where an expression is valid, then it is a requires-expression. This can be determined by the structure of the parse tree, not the *contents* of the parse tree (the specifics of how an identifier gets defined would be the contents of the tree). – Nicol Bolas Jan 15 '19 at 17:42
  • 1
    What I mean is that then it could just as well be for example "requires constraint". – Robert Andrzejuk Jan 15 '19 at 19:31
  • 9
    @RobertAndrzejuk: Sure, the requires-expression could have used a different keyword. But keywords have *huge* costs in C++, as they have the potential to break any program that used the identifier that has become a keyword. The concepts proposal already introduced two keywords: `concept` and `requires`. Introducing a third, when the second would be able to cover both cases with no grammatical issues and few user-facing problems, is just wasteful. After all, the only visual problem is that the keyword happens to be repeated twice. – Nicol Bolas Jan 15 '19 at 19:36
  • 4
    @RobertAndrzejuk it's bad practice anyway to inline constraints like that since you don't get subsumption as if you had written a concept. So taking an identifier for such a low use not recommended feature isn't a good idea. – Rakete1111 Jan 15 '19 at 20:08
  • 2
    In general, you can't parse C++ at all without knowing which names are types and which names are templates, so I don't like the particular example given. But ambiguities are easy to find: this is very similar to the most vexing parse. – T.C. Jan 16 '19 at 05:40
  • Why can't the syntax be: `requires concept (T x) { x + x; }`? That looks like something that must have been considered. – Leo Heinsaar Dec 02 '19 at 19:42
  • @LeoHeinsaar: That doesn't actually fix the problem: `concept name = concept(T x) { x + x; }` is just as repetitive. The problem is that you have 3 structures but don't want to make 3 keywords. – Nicol Bolas Dec 02 '19 at 20:31
  • @NicolBolas I'm not very proficient in the grammar-related aspects, but on the surface at least this looks a lot like the issue of space that was used to be required by the grammar in the double angle brackets of `vector>` that was 'fixed' compiler after compiler until it was essentially recognized as fixable and standardized. :-) – Leo Heinsaar Dec 02 '19 at 21:00
  • @LeoHeinsaar: This isn't a parsing problem; it's a repeated-keyword problem. `concept name = concept` is just as bad in terms of repetition as `requires requires`. If you think one is wrong, then the other is wrong too. – Nicol Bolas Dec 02 '19 at 22:37
  • @NicolBolas To avoid repeating keywords there too, perhaps `auto name = concept` would do, or omitting the second `concept` as in `concept name = (T x) { x + x; }` ("concept lambdas"). – Leo Heinsaar Dec 03 '19 at 06:14
  • @LeoHeinsaar: But you need to be able to use what we currently call a `requires` expression *outside* of a concept definition, so you need some syntax so that I can put a requires expression in an `if constexpr` or whatever. And you need to be able to define a `concept` that doesn't use a requires expression, so we're now back to that whole bit of having the parser assume that `(T)` means one thing or the other. The only truly good solution here is a third keyword; absent that, repeating one of the others is adequate. – Nicol Bolas Dec 03 '19 at 06:19
  • I think I saw `requires requires requires` somewhere. – Spencer May 10 '23 at 17:09
86

The situation is exactly analogous to noexcept(noexcept(...)). Sure, this sounds more like a bad thing than a good thing, but let me explain. :) We'll start with what you already know:

C++11 has "noexcept-clauses" and "noexcept-expressions." They do different things.

  • A noexcept-clause says, "This function should be noexcept when... (some condition)." It goes on a function declaration, takes a boolean parameter, and causes a behavioral change in the declared function.

  • A noexcept-expression says, "Compiler, please tell me whether (some expression) is noexcept." It is itself a boolean expression. It has no "side effects" on the behavior of the program — it's just asking the compiler for the answer to a yes/no question. "Is this expression noexcept?"

We can nest a noexcept-expression inside a noexcept-clause, but we typically consider it bad style to do so.

template<class T>
void incr(T t) noexcept(noexcept(++t));  // NOT SO HOT

It's considered better style to encapsulate the noexcept-expression in a type-trait.

template<class T> inline constexpr bool is_nothrow_incrable_v =
    noexcept(++std::declval<T&>());  // BETTER, PART 1

template<class T>
void incr(T t) noexcept(is_nothrow_incrable_v<T>);  // BETTER, PART 2

The C++2a Working Draft has "requires-clauses" and "requires-expressions." They do different things.

  • A requires-clause says, "This function should participate in overload resolution when... (some condition)." It goes on a function declaration, takes a boolean parameter, and causes a behavioral change in the declared function.

  • A requires-expression says, "Compiler, please tell me whether (some set of expressions) is well-formed." It is itself a boolean expression. It has no "side effects" on the behavior of the program — it's just asking the compiler for the answer to a yes/no question. "Is this expression well-formed?"

We can nest a requires-expression inside a requires-clause, but we typically consider it bad style to do so.

template<class T>
void incr(T t) requires (requires(T t) { ++t; });  // NOT SO HOT

It's considered better style to encapsulate the requires-expression in a type-trait...

template<class T> inline constexpr bool is_incrable_v =
    requires(T t) { ++t; };  // BETTER, PART 1

template<class T>
void incr(T t) requires is_incrable_v<T>;  // BETTER, PART 2

...or in a (C++2a Working Draft) concept.

template<class T> concept Incrable =
    requires(T t) { ++t; };  // BETTER, PART 1

template<class T>
void incr(T t) requires Incrable<T>;  // BETTER, PART 2
Quuxplusone
  • 23,928
  • 8
  • 94
  • 159
  • 1
    I don't really buy this argument. `noexcept` has the problem that `noexcept(f())` could mean _either_ interpret `f()` as a boolean that we're using to set the specification _or_ check whether or not `f()` is `noexcept`. `requires` doesn't have this ambiguity because the expressions its checking for validity already have to be introduced with `{}`s. After that, the argument is basically "the grammar says so." – Barry Jan 16 '19 at 03:29
  • @Barry: See [this comment](https://stackoverflow.com/questions/54200988/why-do-we-require-requires-requires#comment95242504_54201224). It appears the `{}` are optional. – Eric Jan 16 '19 at 06:48
  • 1
    @Eric The `{}` are not optional, that's not what that comment shows. However, that is a great comment demonstrating parsing ambiguity. Would probably accept that comment (with some explanation) as a standalone answer – Barry Jan 16 '19 at 13:06
  • 1
    `requires is_nothrow_incrable_v;` should be `requires is_incrable_v;` – Ruslan Jan 16 '19 at 14:32
  • is_incrementible??? Apparently, there is not a well-established English word for "can be incremented" but I'm guessing here that this is more correct??? – Daniel Russell Aug 14 '21 at 02:11
  • Sorry, should be `is_incrementable` based on the standard's `std::incrementable_traits`, i.e. with an 'a' instead of 'i'. – Daniel Russell Aug 14 '21 at 02:28
32

I think cppreference's concepts page explains this. I can explain with "math" so to say, why this must be like this:

If you want to define a concept, you do this:

template<typename T>
concept Addable = requires (T x) { x + x; }; // requires-expression

If you want to declare a function that uses that concept, you do this:

template<typename T> requires Addable<T> // requires-clause, not requires-expression
T add(T a, T b) { return a + b; }

Now if you don't want to define the concept separately, I guess all you have to do is some substitution. Take this part requires (T x) { x + x; }; and replace the Addable<T> part, and you'll get:

template<typename T> requires requires (T x) { x + x; }
T add(T a, T b) { return a + b; }

which explains the mechanics. The why is best illustrated with an example of the ambiguity that would result if we changed the language to accept a single requires as a shorthand for requires requires.

constexpr int x = 42;

template<class T>
void f(T) requires(T (x)) { (void)x; };

template<class T>
void g(T) requires requires(T (x)) { (void)x; };

int main(){
    g<bool>(0);
}

View in Godbolt to see the compiler warnings, but note that Godbolt doesn't try the link step, which would fail in this case.

The only difference between f and g is the doubling up of 'requires'. Yet the semantic difference between f and g is enormous:

  • g is just a function declaration, f is a full definition
  • f accepts only bool, g accepts every type castable to void
  • g shadows x with its own (superfluously parenthesized) x, but
  • f casts the global x to the given type T

Obviously we wouldn't want the compiler to change one into the other automatically. This could have been solved by using a separate keyword for the two meanings of requires, but when possible C++ tries to evolve without introducing too many new keywords, as that breaks old programs.

TamaMcGlinn
  • 2,840
  • 23
  • 34
The Quantum Physicist
  • 24,987
  • 19
  • 103
  • 189
  • 4
    I don't think is what the question is asking for. This is explaining the grammar, more or less. – Passer By Jan 15 '19 at 14:50
  • But why can't you have `template requires (T x) { x + x; }` and require that require can be both the clause and the expression? – NathanOliver Jan 15 '19 at 14:50
  • 2
    @NathanOliver: Because you're forcing the compiler to interpret one construct as another. A `requires`-as-constraint clause does not *have to* be a `requires`-expression. That's merely one possible use of it. – Nicol Bolas Jan 15 '19 at 14:51
  • @NathanOliver I don't think there's some magical answer to this. It's just ambiguous, and the compiler has certain expectations so that it parses things correctly. Probably in the next C++ version, if they find it not to be ambiguous, they can support that. – The Quantum Physicist Jan 15 '19 at 14:55
  • 2
    @TheQuantumPhysicist What I was getting at with my comment is this answer just explains the syntax. Not what actual technical reason we have to `requires requires`. They could have added something to the grammar to allow `template requires (T x) { x + x; }` but they didn't. Barry wants to know why they didn't – NathanOliver Jan 15 '19 at 14:58
  • @NathanOliver I don't think there is an answer to this question. It completely and totally adds up from a syntactic point of view (like Nicol explained). Again, maybe in the next C++ version they'll allow it and it's still not obvious whether it's unambiguous. I'm not sure Barry is asking about that though. – The Quantum Physicist Jan 15 '19 at 15:03
  • 7
    If we're really playing find-the-grammar-ambiguity here, OK, I'll bite. https://godbolt.org/z/i6n8kM `template void f(T) requires requires(T (x)) { (void)x; };` means something different if you remove one of the `requires`es. – Quuxplusone Jan 15 '19 at 22:43
  • Missed opportunity to use a `template template` parameter there while demonstrating `requires requires` – Mark K Cowan Jan 16 '19 at 17:36
  • @Quuxplusone that example is amazing. Could you elaborate though, on what the difference is? It looks to me as if g is just a function declaration which requires the template parameter to be castable to void (so, everything matches), while f is also a definition but I'm not sure. – TamaMcGlinn Jul 16 '21 at 09:48
  • 1
    @TamaMcGlinn: I think you've got it. In [the godbolt I posted above](https://godbolt.org/z/71jhr3Ksc), the `f` with one `requires` is a definition: it is constrained on `(T(x))`, i.e. `(bool(42))` (since `T` is `bool`), i.e. `true`. Its body is `{ (void)x; }`, with a superfluous trailing `;`. The `g` with `requires requires` is a declaration constrained on `requires (T (x)) { (void)x; }`, which is OK for all `T` (except cv-qualified `void`, and [arguably](https://godbolt.org/z/9cGconY6G) abominable types); and it has no body. – Quuxplusone Jul 16 '21 at 19:51
  • I see; godbolt apparently doesn't run the linker, so that explains why it seemed to accept calling `g(0);` from main, but that indeed fails at link-time as expected when I try it locally. Using f is of course fine, it has a definition which casts the parameter to void and does nothing with it. – TamaMcGlinn Jul 17 '21 at 08:00
  • [clang -Weverything](https://godbolt.org/z/8nKKencKM) helps; (1) redundant parentheses around formal parameter name in the requires clause for g - which are useful for f. (2) the function definition f has an extra trailing `;` - for g this is necessary because it is just a declaration. (3) shadowing x - we need x to be a global so that f can have this restraint that just casts the value of x to some type T and checks that the result is `true` - whereas g has a requires clause that introduces a new x, shadowing the global one. If the global x = 0, calling f is impossible. – TamaMcGlinn Jul 17 '21 at 08:13
18

I found a comment from Andrew Sutton (one of the Concepts authors, who implemented it in gcc) to be quite helpful in this regard, so I thought I'd just quote it here in its near-entirety:

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.

Barry
  • 286,269
  • 29
  • 621
  • 977
-14

Because you are saying that a thing A has a requirement B, and the requirement B has a requirement C.

The thing A requires B which in turn requires C.

The "requires" clause itself requires something.

You have thing A (requiring B (requiring C)).

Meh. :)

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
  • 5
    But according to the other answers, the first and second `requires` are not conceptually the same thing (one is a clause, one an expression). In fact, if I understand correctly, the two sets of `()` in `requires (requires (T x) { x + x; })` have very different meanings (the outer being optional and always containing a boolean constexpr; the inner being a mandatory part of introducing a requires expression and _not_ allowing actual expressions). – Max Langhof Jan 15 '19 at 15:28
  • 2
    @MaxLanghof Are you saying that the requirements differ? :D – Lightness Races in Orbit Jan 15 '19 at 15:42