5.2.18 · D3C++ Programming

Worked examples — Concepts (C++20) — constraining templates

3,572 words16 min readBack to topic

This page is the "throw every ball at it" drill for C++20 concepts. We will not just use concepts — we will hunt down every kind of situation a constraint can face and work each one fully, so you never meet a case you haven't already seen resolved.


The scenario matrix

Think of each row as one "cell" the topic can hand you. Every worked example below is tagged with the cell(s) it covers.

# Cell class Concrete trigger What we must show
C1 Satisfied int vs Numeric constraint passes, body compiles
C2 Fails, but another overload still matches std::string between Numeric and a fallback one candidate dropped, the other is chosen
C3 All fail → hard error no candidate survives the clean "no matching function" message
C4 Two overloads, one applies int between integral/floating_point disjoint constraints, exactly one wins
C5 Two overloads, both apply → subsumption int between Integral and SignedIntegral more-constrained wins
C6 Ambiguous, neither subsumes two unrelated requires compiler error: ambiguous call
C7 Compound requirement (type of result) { a+b } -> same_as<T> expression valid and returns T
C8 Nested / word problem a real "printable range" build a multi-part concept, real container
C9 Degenerate inputs empty range, void, self-referential type limiting behaviour, no crash
C10 Exam twist requires requires, short-circuit of `

We now cover C1–C10 across 10 examples (one per cell).


Example 1 — C1: the simplest "yes"


Example 2 — C2: one overload fails, but a fallback still matches


Example 3 — C3: every overload fails → the clean hard error


Example 4 — C4: two disjoint overloads, exactly one applies


Example 5 — C5: both apply, subsumption picks the stronger

Figure — Concepts (C++20) — constraining templates

Example 6 — C6: both apply, neither subsumes → ambiguous


Example 7 — C7: compound requirement constrains the result type

Before the example, we must earn one new piece of notation: the -> inside a requires block.


Example 8 — C8 (word problem): a printable-range concept on a real container

Figure — Concepts (C++20) — constraining templates

Example 9 — C9: degenerate & limiting inputs


Example 10 — C10 (exam twist): requires requires and || short-circuit


Recall Which cell does each example cover?

Example 1 :::> C1 satisfied Example 2 :::> C2 one overload fails, fallback still matches Example 3 :::> C3 all fail → hard error (no matching function) Example 4 :::> C4 disjoint overloads, one applies Example 5 :::> C5 subsumption, stronger wins Example 6 :::> C6 ambiguous, neither subsumes Example 7 :::> C7 compound requirement / result type Example 8 :::> C8 nested concept, real container (word problem) Example 9 :::> C9 degenerate: empty range, void, self-reference Example 10 :::> C10 exam twist: requires requires + || short-circuit


Parent: Concepts (C++20) — constraining templates · Prereqs: Templates — function & class templates, SFINAE and std::enable_if, type_traits — std::integral, std::floating_point, Overload Resolution & Subsumption, constexpr — compile-time evaluation, Ranges library (C++20), auto and decltype.