A concept is a set of restrictions on template parameters, which are evaluated at compile time. We can use a concept in class and function templates to manage function overloads and partial specializations. C++ 20 provides
There are three ways to use a concept with a class:
requires
clauserequires
clauseIn this shot, we will write a concept in a class using the requires
clause.
Note: If you want to learn all the three ways to use a concept with a class, then you should check out this course.
requires
clauseWe will use the same incomplete Number
concept for the built-in numeric types that we used in this shot.
#include <concepts>template <typename T>concept Number = std::integral<T> ||std::floating_point<T>;
We can use the requires
clause to define class template limits. We will create a class template, and after the template parameter list, we will add a requires
clause on line 8, with restrictions that apply to our input.
#include <concepts>#include <iostream>template <typename T>concept Number = std::integral<T> || std::floating_point<T>;template <typename T>requires Number<T>class WrappedNumber {public:WrappedNumber(T num) : m_num(num) {}private:T m_num;};int main() {WrappedNumber wn{42};// WrappedNumber ws{"a string"}; // template constraint failure for 'template<class T> requires Number<T> class WrappedNumber'}
As we can see in the example, this is the same as the template
class, except for the additional line of the requires
clause.
If we use the template type name T
in multiple places, the values we replace must be of the same type. If we use two restricted T
s in the constructor, they must also be of the same type. Even if both of them satisfy the concept of Number
, they cannot be called by int
and float
.
A different declaration is required for the template parameter list and the potentially different usage limits for the template parameters.
#include <concepts>#include <iostream>template <typename T>concept Number = std::integral<T> || std::floating_point<T>;template <typename T, typename U>requires Number<T> && Number<U>class WrappedNumber {public:WrappedNumber(T num, U anotherNum) : m_num(num), m_anotherNum(anotherNum) {}private:T m_num;U m_anotherNum;};int main() {WrappedNumber wn{42, 5.4f};}
Line 9 of the code example given above shows that we can use compound expressions as constraints. That’s not possible with the other way to write constrained template classes.
Free Resources