Why are parentheses needed around negated expressions in a requires-clause?

Viewed 408

The following code is an usage example of the requires-clause:

#include <type_traits>

template <typename T>
  requires std::is_integral_v<T>
void take_integral(T value);

It accepts an expression that evalutes to a bool value (std::is_integral_v<T> in this case), and works as expected. However, when such expression is negated with the ! operator, it results in a compilation error:

#include <type_traits>

template <typename T>
  requires !std::is_integral_v<T>
void take_integral(T value);

Diagnostic from GCC:

<source>:4:12: error: expression must be enclosed in parentheses
    4 |   requires !std::is_integral_v<T>
      |            ^~~~~~~~~~~~~~~~~~~~~~
      |            (                     )
Compiler returned: 1

Diagnostic from Clang:

<source>:4:12: error: parentheses are required around this expression in a requires clause
  requires !std::is_integral_v<T>
           ^~~~~~~~~~~~~~~~~~~~~~
           (                     )
1 error generated.
Compiler returned: 1

Why are parentheses needed here?

1 Answers

Parentheses are required because they avoid language parsing ambiguities.

Not every expression is allowed inside a requires-clause. In fact, the standard gives an example of how a parsing ambiguity would arise if all expressions were allowed:

[temp.pre]/9

[...] The expression in a requires-clause uses a restricted grammar to avoid ambiguities. Parentheses can be used to specify arbitrary expressions in a requires-clause. [ Example:

template<int N> requires N == sizeof new unsigned short
int f();            // error: parentheses required around == expression

— end example ]

In the above example given by the standard, a compiler couldn't possibly know whether the sizeof part should be parsed as a sizeof of the expression new unsigned short or new unsigned short int. Putting parentheses around it, like requires (N == sizeof new unsigned short), solves the problem.

Related