...

/

Create Safer Templates with Concepts and Constraints

Create Safer Templates with Concepts and Constraints

Discover the way to create safer templates with concepts and constraints.

We'll cover the following...

TemplatesIn C++, a template is a way to define a generic class or function without specifying the data type(s) it will work with. are great for writing code that works with different types. For example, this function will work with any numeric type:

template <typename T>
T arg42(const T & arg) {
return arg + 42;
}

But what happens when we try to call it with a non-numeric type?

const char * n = "7";
cout << "result is " << arg42(n) << "\n";

Output:

Result is ion

This compiles and runs without error, but the result is unpredictable. In fact, the call is dangerous and it could easily crash or become a vulnerability. It would be helpful if the compiler generated an error message, so we can fix the code.

Now, with concepts, it can be written like this:

template <typename T>
requires Numeric<T>
T arg42(const T & arg) {
return arg + 42;
}

The requires keyword is new for C++20. It applies constraints to a template. Numeric is the name of a concept that only accepts integer and floating-point types. Now, when this code is compiled with a non-numeric parameter, it gives a reasonable compiler error:

error: 'arg42': no matching overloaded function found
error: 'arg42': the associated constraints are not satisfied

Error messages like this are far more useful than most compiler errors.

Let's take a closer look at how to use concepts and constraints in our code.

How to do it

A concept is simply a named constraint. The Numeric concept from above looks like this:

#include <concepts>
template <typename T>
concept Numeric = integral<T> || floating_point<T>;

This concept requires a type T, which satisfies either the std::integral or std::floating_point ...