Why do we require requires requires?

Someone on StackOverflow just asked about the silly-looking requires requires syntax that’s used a few times in the C++2a Working Draft and in the Ranges library implementation. Since I had just written slides on this for my presentation at the NYC C++ meetup last week, and my explanation seemed well-received there, I gave an answer on SO. I’m repeating it verbatim here, for visibility. TLDR: requires requires is not grammatically insane; but it is questionable style, and you should know how to eliminate it from your code. We show all these things by analogy to noexcept(noexcept(...)).


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

See also: A modest proposal for a GCC diagnostic.

Posted 2019-01-15