Syntactic Overview of Constraints and Concepts
Learn about concepts and constraints in coding, including function overloading and standard library concepts.
This section is a short introduction to constraints and concepts. We will not cover them completely in this course, but we will provide enough material to be productive.
Defining new concepts
Defining new concepts is straightforward with some help from the type traits that you are already familiar with. The following example defines the concept FloatingPoint
using the keyword
concept:
template <typename T>concept FloatingPoint = std::is_floating_point_v<T>;
The right-hand side of the assignment expression is where we can specify the constraints of the type T
. Combining multiple constraints using ||
(logical OR*) and &&
(logical AND) is also possible. The following example uses ||
to combine floats and integrals into a Number concept:
template <typename T>concept Number = FloatingPoint<T> || std::is_integral_v<T>;
We will note that it’s possible to build concepts using already defined concepts on the right-hand side as well. The standard library contains a <concepts>
header, which defines many useful concepts, such as std::floating_point
(which we should use rather than define ourselves).
Furthermore, we can use the requires
keyword to add a set of statements that should be added to our concept definition. For example, this is the definition of the concept std::range
from the Ranges library:
template <typename T>concept Range = requires(T& t) {begin(t);end(t);};
In short, this concept states that a range is something that we can pass to std::ranges::begin()
and std::ranges::end()
.
It’s possible to write more sophisticated requires
clauses than ...