Lesson 17 / 25
Concepts and Constraints (C++20)
Constrain templates with concepts for clearer interfaces and errors.
Saying what a type must support
Before C++20, template requirements were implicit: if you called sort on something without operator<, you got pages of errors from deep inside the library. Concepts make requirements explicit. A concept is a named compile-time predicate on types, such as the standard std::integral, std::floating_point, std::totally_ordered, std::copyable, std::invocable and std::ranges::range. Use them to constrain templates: template <std::integral T> T gcd(T a, T b), or with the abbreviated syntax auto gcd(std::integral auto a, std::integral auto b). Write your own with requires expressions that list valid operations: concept Shape = requires(const T& s) { { s.area() } -> std::convertible_to<double>; };. Calls with unsuitable types now fail at the call site with a short message naming the unmet concept. Concepts also enable overloading on constraints: the compiler picks the most constrained matching overload. Earlier techniques such as SFINAE and std::enable_if achieved similar effects with much more obscure code.
Standard and custom concepts
A call with the wrong type fails with a clear concept error.
#include <concepts>
#include <numbers>
#include <vector>
template <std::integral T>
T gcd(T a, T b) {
while (b != 0) { T t = a % b; a = b; b = t; }
return a;
}
template <typename T>
concept Shape = requires(const T& s) {
{ s.area() } -> std::convertible_to<double>;
};
struct Circle { double r; double area() const { return std::numbers::pi * r * r; } };
struct Rect { double w, h; double area() const { return w * h; } };
double total_area(const std::vector<Circle>& cs) {
double t = 0; for (const auto& c : cs) t += c.area(); return t;
}
double area_of(const Shape auto& s) { return s.area(); } // abbreviated template syntax
int main() {
auto g = gcd(84, 36); // 12
// gcd(3.5, 1.5); // error: double does not satisfy std::integral
double a = area_of(Rect{3, 4});
// area_of(42); // error: int does not satisfy Shape
}Job requirements on a posting
Before concepts, a template was a job posting with no requirements listed: unsuitable applicants were rejected only after a long, confusing interview. Concepts print the requirements on the posting, so mismatches are caught at the door.
Quick check: What is the main benefit of C++20 concepts?
- They make programs run faster
- They state template requirements explicitly, giving clearer interfaces and error messages
- They replace classes
- They enable garbage collection
Answer
They state template requirements explicitly, giving clearer interfaces and error messages — Concepts document and check requirements on template arguments at the call site.