C++advancedcpp20

Templates and concepts

Write one definition that works for many types, then constrain it with C++20 concepts so misuse fails early with a readable message.

Function and class templates generate code per type; C++20 concepts and requires clauses replace cryptic SFINAE with named, composable constraints the compiler checks up front.

A template is a recipe: you write the logic once with a placeholder type parameter, and the compiler stamps out a concrete version β€” an instantiation β€” for each type you actually use. template <typename T> introduces that parameter, and from then on T behaves like a real type inside the body. Nothing is generated until you call or instantiate the template with a concrete type, so unused templates cost nothing at runtime.

The two everyday forms are function templates (max(a, b) for any comparable type) and class templates (Box<int>, Box<std::string> β€” one class definition, many specialised types). The compiler deduces type arguments from the call where it can, so max(3, 4) needs no angle brackets.

Constraining with concepts

Plain templates accept any type, so a mistake surfaces deep inside the instantiated body as a wall of errors. C++20 concepts fix this: a concept is a named, compile-time boolean predicate over types. Attach one as a constraint and the compiler rejects bad arguments at the call site with a message that names the unmet requirement, instead of failing twenty lines into the template.

You write constraints with a requires clause or by using the concept directly in place of typename: template <std::integral T> means "T must satisfy std::integral". The standard library ships many ready-made concepts in <concepts> (std::integral, std::floating_point, std::same_as, std::convertible_to), and a requires expression lets you assert that specific operations compile.

Composing and abbreviating

Concepts compose with && and ||, so you can build precise requirements like "integral or floating point" without bespoke trait classes. And because a concept is a type constraint, you can use it where auto would go: void f(std::integral auto x) is a constrained auto β€” a terse function template whose single parameter is restricted to integral types. This is the same machinery as a full template header, just abbreviated.

Try it 4 examples

A function template deduced from its arguments

C++intro
0ms
82.5pear8
Reference Β· output compiled offline, not runnable in-browser

One myMax definition serves three types β€” int, double, and std::string (where pear wins lexicographically) β€” with T deduced from each call. The final 8 comes from myMax<double>(3, 8), where pinning T=double converts both int arguments and the result prints as 8.