Article
Demystifying C++20 Requires-Clauses
December 1, 2019
C++20 introduces requires-clauses for constraining templates. They are already usable in current trunk versions of GCC and Clang on Compiler Explorer. Below is the minimal form:
template<typename T>
requires is_standard_layout_v<T> && is_trivial_v<T>
void fun(T v);
fun(1); // OK
fun(std::string{}); // errorTwo-step check
First the compiler verifies that every operand is well-formed. If any expression is ill-formed the whole constraint is considered not satisfiedrather than a hard error.
template<typename T> requires is_trivial_v<typename T::value_type> void g(T x); // enabled only if T::value_type exists g(1); // falls back to other overloads
Parentheses matter
template<typename T> requires (!is_trivial_v<T>) // OK void f1(T); template<typename T> requires !is_trivial_v<T> // ill-formed void f2(T);
Conjunction & disjunction
template<typename T, typename U>
requires std::is_trivial_v<typename T::value_type>
|| std::is_trivial_v<typename U::value_type>
void h(T, U);Sub-constraints are evaluated left-to-right and stop once the result is known.
Variadic constraints
template<typename T> concept TrivVT = std::is_trivial_v<typename T::value_type>; template<typename... Ts> requires (TrivVT<Ts> || ...) void pack_fun(Ts...);
Overload selection
template<typename T>
void ovl(T) { std::cout << "generic"; }
template<typename T>
requires std::is_integral_v<T>
void ovl(T) { std::cout << "integral"; }
ovl(1); // integral
ovl("x"); // genericKey points
- Constraint operands must be well-formed; failure disables the template.
- Wrap complex predicates in parentheses to avoid parsing issues.
||and&&inside requires-clauses denote constraint disjunction/conjunction with lazy evaluation.- Using concepts enables automatic ordering of more-constrained overloads.