thecodex.expert · The Codex Family of Knowledge
C++

Concepts and Constraints

Passing the wrong type to an unconstrained template before C++20 could produce hundreds of lines of nearly unreadable template-instantiation error — concepts turn that into one short, direct sentence.

C++20 / C++23 Since C++20 Last verified:
Canonical Definition

A concept, declared with the concept keyword, names a compile-time predicate over a type — std::integral, std::copyable, or a hand-written one combining requires clauses. Applying a concept to a template parameter (template <std::integral T>, or the equivalent requires clause) makes the compiler check that constraint immediately at the call site, producing a short, specific error naming exactly which requirement failed, rather than the deeply nested instantiation errors that unconstrained templates historically produced when a mismatched type was used somewhere deep inside the template body.

Using a built-in standard concept

The compiler rejects add("a", "b") immediately with a clear message naming std::integral as the unsatisfied constraint, rather than letting the call proceed into the function body and fail confusingly on the + operator deep inside.

C++basic_concept.cpp
template <std::integral T>   // constrains T to integer types only
T add(T a, T b) {
    return a + b;
}

add(3, 4);         // fine — int satisfies std::integral
// add("a", "b");   // COMPILE ERROR: clearly states std::integral isn't satisfied by const char*

Writing a custom concept

requires { ... } checks that the given expressions are valid for T — here, a type qualifies as Printable only if it can genuinely be streamed to std::cout, checked directly rather than assumed.

C++custom_concept.cpp
template <typename T>
concept Printable = requires(T t) {
    { std::cout << t };   // T must support being streamed to std::cout
};

template <Printable T>
void print(T value) {
    std::cout << value << "\n";
}

requires clauses: an alternative syntax

This form is equivalent to the angle-bracket constraint syntax but reads more like an ordinary if condition, often preferred when combining multiple constraints together.

C++requires_clause.cpp
template <typename T>
requires std::integral<T> && std::signed_integral<T>
T abs_value(T x) {
    return x < 0 ? -x : x;
}

Sources

1
ISO/IEC 14882 (C++ Standard), "Constraints and concepts," cppreference.com/w/cpp/language/constraints.