🔑Go deeper — read the bookC++ Keywords by Version — Specifiers & Attributes— runnable code & full walkthrough →

cpp20 · advanced

C++20 Concepts & requires — Type Constraints Made Explicit

C++20 concepts let you attach named, checked constraints to template parameters. A concept is a compile-time boolean predicate defined with the 'requires' expression: you list expressions that must compile ({a+b}->same_as<T>) and nested boolean requirements (requires is_arithmetic_v<T>). When a call site provides a type that fails any requirement, the compiler immediately reports which constraint was violated — instead of the 50+ line instantiation error you'd get from unconstrained templates. Concepts also enable if constexpr branching and are used in overload resolution: the most-constrained satisfying overload wins. They replace most SFINAE / enable_if patterns with readable, self-documenting syntax.

🔑 Key line

A C++20 concept is a compile-time named predicate over a type: concept Name = requires(T a){ {expr}->Type; requires bool_const; }; the compiler checks it at the call site before instantiation, giving clear errors naming the violated constraint instead of template noise.

The code

// 1. Define a concept
template <typename T>
concept Numeric = requires(T a, T b) {
{ a + b } -> std::same_as<T>; // valid expression + return type
{ a * b } -> std::same_as<T>;
requires std::is_arithmetic_v<T>; // nested requirement
};
// 2. Use it — constrained template
template <Numeric T> // shorthand: requires Numeric<T>
T add(T a, T b) {
return a + b;
}
// 3. Concept in if constexpr / requires clause
template <typename T>
void process(T val) {
if constexpr (Numeric<T>) // compile-time branch
std::cout << val + val;
else
std::cout << "non-numeric";
}
add(1, 2); // T=int → Numeric<int>=true ✓
add(1.5, 2.5); // T=double → Numeric<double>=true ✓
add("x", "y"); // T=const char* → false: no arithmetic ✗

What this lesson walks through

  1. 01What is a C++20 concept?
  2. 02requires expression: checking valid expressions and return types
  3. 03Highlight: nested requirement is_arithmetic_v<T>
  4. 04int satisfies Numeric — constraint check
  5. 05const char* violates Numeric — immediate, readable error
  6. 06Constrained vs unconstrained — why concepts matter
  7. 07if constexpr + concepts: compile-time branching on type traits

A concept is a named, compile-time predicate over a type or value. It lets you express constraints on template parameters in readable, checked English-like syntax. Before C++20 you needed SFINAE or enable_if — with concepts the intent is explicit.

See it animated — step by step, at your own pace

Unlock the full interactive walkthrough of C++20 Concepts & requires — Type Constraints Made Explicit and 100+ animated C++ interview lessons.

← Previous
C++17: inline Variables
Next →
C++20 Coroutines — co_yield, co_await, co_return