C++

Concepts & Constraints

10 question(s)

What are C++20 concepts?

Beginner
Concepts are named, compile-time predicates that constrain template parameters—specifying the requirements a type must satisfy (e.g., must be sortable, must support +). They make templates clearer, produce far better error messages than raw templates or SFINAE, and let the compiler reject invalid types early with a precise reason.
template <std::integral T>
T doubleIt(T x) { return x + x; }   // T must be an integer type
Real-world example Constraining a numeric template with std::integral gives a clear error when a string is passed.

Common follow-ups: What do concepts constrain? | How do they improve error messages?

Templates Concepts & Constraints Concepts & Constraints

How do concepts improve template error messages?

Beginner
Without concepts, using a template with an unsupported type produces long, cryptic errors deep inside the template's body. Concepts check requirements at the call site and report a concise message like 'constraint not satisfied' naming the failed requirement, so mistakes are caught early and explained clearly.
template <class T> requires std::equality_comparable<T>
bool same(T a, T b) { return a == b; }
Real-world example Passing a non-comparable type now yields 'does not satisfy equality_comparable' instead of a wall of template errors.

Common follow-ups: Where is the constraint checked? | What kind of message do you get?

Templates Concepts & Constraints Concepts & Constraints

What are the different ways to apply a constraint to a template?

Intermediate
You can constrain templates via: a concept name in place of typename (template <std::integral T>), a requires clause (template <class T> requires C<T>), a trailing requires clause after the function signature, or the abbreviated function template syntax using a concept with auto (void f(std::integral auto x)). All express the same kind of requirement.
void f(std::integral auto x);         // abbreviated
template <class T> requires C<T> void g(T);  // requires clause
Real-world example The team uses the abbreviated 'std::sortable auto' parameter form for concise constrained functions.

Common follow-ups: What is the abbreviated function template syntax? | What is a requires clause?

Templates Type Deduction & auto Concepts & Constraints

What is a requires expression?

Intermediate
A requires expression (requires(T a){ ... }) is a compile-time check that yields true if the enclosed operations/requirements are valid for the given types. It's used to define concepts, listing required expressions, their validity, and return-type constraints. It replaces verbose SFINAE with readable requirement lists.
template <class T>
concept Addable = requires(T a, T b) { { a + b } -> std::same_as<T>; };
Real-world example A custom Addable concept is defined with a requires expression listing that a + b must be valid and return T.

Common follow-ups: What does a requires expression evaluate to? | How does it define a concept?

Templates Concepts & Constraints Concepts & Constraints

How do concepts compare to SFINAE and enable_if?

Advanced
SFINAE with std::enable_if constrains templates by making invalid substitutions silently remove overloads—powerful but cryptic and hard to read/maintain. Concepts express the same constraints declaratively, give clear diagnostics, participate cleanly in overload resolution (more-constrained overloads are preferred), and are far more readable. Concepts are the modern replacement for most SFINAE.
// old: template <class T, std::enable_if_t<std::is_integral_v<T>>* = nullptr>
// new: template <std::integral T>
Real-world example Rewriting enable_if-heavy code with concepts makes constraints readable and error messages clear.

Common follow-ups: Why are concepts more readable than SFINAE? | How do they affect overload resolution?

Templates Concepts & Constraints Concepts & Constraints

What are some standard library concepts?

Beginner
The standard library defines many concepts in <concepts> and elsewhere: std::integral, std::floating_point, std::same_as, std::convertible_to, std::equality_comparable, std::totally_ordered, std::copyable, std::movable, std::invocable, and range/iterator concepts. They cover common type requirements so you rarely need to write your own.
template <std::floating_point T> T half(T x){ return x/2; }
Real-world example Constraining math helpers with std::floating_point documents and enforces that only real-number types are accepted.

Common follow-ups: Where are standard concepts defined? | Name a few common ones.

Templates Concepts & Constraints Concepts & Constraints

How do you define a custom concept?

Advanced
Define a concept with the concept keyword equal to a compile-time boolean expression, often a requires expression listing required operations and their constraints. The concept can then constrain templates. Compose concepts with && and || and refine existing ones to build precise, reusable requirements.
template <class T>
concept Container = requires(T c) {
    c.begin(); c.end(); typename T::value_type;
};
Real-world example A project defines a Container concept so generic algorithms clearly require begin/end and value_type.

Common follow-ups: How do you compose concepts? | What is a refined concept?

Templates Concepts & Constraints Concepts & Constraints

How does concept subsumption affect overload resolution?

Intermediate
When multiple constrained overloads match, the compiler prefers the one whose constraints subsume (are more specific/stronger than) the others. This lets you write a general constrained template plus a more-constrained specialization, and the most-constrained viable candidate is chosen—cleanly replacing tag dispatch and enable_if priority tricks.
void f(std::integral auto x);              // more constrained
void f(auto x);                            // less constrained
f(5);   // picks the std::integral overload
Real-world example A more-constrained overload for random-access ranges is automatically preferred over the generic one.

Common follow-ups: What does 'subsume' mean? | Which overload is preferred?

Templates Concepts & Constraints Concepts & Constraints

Why use concepts instead of unconstrained templates?

Beginner
Unconstrained templates accept any type and only fail deep inside instantiation with confusing errors, and they can silently participate in overload resolution for wrong types. Concepts document intent, reject invalid types at the interface with clear messages, improve tooling/IDE support, and make generic code self-explanatory and safer.
Real-world example Adding concepts to a library's templates turns baffling instantiation errors into clear, early diagnostics.

Common follow-ups: What problem do unconstrained templates have? | How do concepts document intent?

Templates Concepts & Constraints Concepts & Constraints

How do concepts interact with the ranges library?

Advanced
The ranges library is built on concepts: it defines iterator and range concepts (input_iterator, sized_range, etc.) that constrain every algorithm and view, so misuse is caught at compile time with clear messages, and adaptors compose only with compatible ranges. Concepts are foundational to ranges' safety and expressiveness.
Real-world example A view adaptor that needs a forward range fails to compile clearly when given a single-pass input range.

Common follow-ups: What concepts underpin ranges? | How do they make ranges safer?

Ranges & Views Templates Concepts & Constraints