Search⌘ K
AI Features

The Four Ways to Use Concepts

Explore the four distinct ways to use C++20 Concepts in function templates to enforce type constraints and improve code clarity. Understand requires clauses, trailing requires clauses, constrained template parameters, and abbreviated function templates to decide which suits your coding needs.

In this section, we’ll learn the four different ways we can use concepts with C++ functions and the four different ways to constrain function templates. Once we understand them and their differences, we’ll see how to choose among the different forms.

Types of concepts

For our examples, let’s assume that we have a concept called Number that requires a built-in arithmetic type of C++. As such, user-defined numeric types are ignored. We’ll use a very simplistic implementation.

We’ll complete the Number concept in a later chapter so that only numbers are accepted. At this point, we’ll start with an oversimplified implementation:

#include <concepts>
template <typename T>
concept Number = std::integral<T> || std::floating_point<T>;

We oversimplified because not only numbers satisfy the C++ std::integral concept, but also bool values and different char types. However, it’s a good enough approximation for our examples.

1. Using the requires clause

In the first way, we use the requires clause between the template parameter list and the function return.

template <typename T>
requires Number<T>

2. Trailing requires clause

We can also use the trailing requires clause that comes after the function parameter list (and the qualifiers const, override, etc., if any) and before the function implementation.

template <typename T>
returnType funcName(T param) requires Number<T> 

3. Constrained template parameter

This way is a bit terser than the previous ones. It also brings some limitations.

template <Number T>

4. Abbreviated function templates

But what if we’re looking for brevity? Here we go!

auto add(Number auto a, Number auto b)