The Trailing Requires Clause

Learn how the trailing `requires` clause can be used to define constraints for the class templates.

How to constrain classes with the trailing requires clause

When we learn that we can use the trailing requires clause with class templates, we might at first think of an implementation like this:

template <typename T>
class WrappedNumber {
public:
    WrappedNumber(T num) : m_num(num) {}
private:
    T m_num;
} requires Number<T>;

However, this doesn’t have any benefits and doesn’t compile. Imagine if we had to scroll down to the end of some long classes just to see these constraints. We can make this more efficient.

Note: The trailing requires clause can be used with class templates on functions.

How to constrain a function of a class template

So far we’ve seen examples of constraining the template parameter for the whole class. But what if we wanted to constrain the usage of a certain function of a class template? Or what if we wanted to provide different implementations based on certain traits of the template parameter type? It’s possible without using the difficult to pronounce and difficult to understand write-only SFINAESFINAE" stands for "substitution failure is not an error.

let’s see how we can restrict the usage of a function based on the type of the class template parameter. In the following example, our Ignition class has a function called insertKey(). However, not all modern cars have keys to insert anymore. In fact, there are fewer and fewer of them and calling insertKey() with “smart” keys does not make much sense.

Therefore, we’d like to find a way to ban the insertKey() function for keys that are considered smart. Although there are different ways to do that, here we’ll focus on the one with concepts. We can restrict function specializations with = delete for whatever types that satisfy certain concepts. In our example, we can’t call the insertKey function with any type that satisfies the Smart concept, while the rest of the types are not affected.

template <typename Key>
class Ignition {
public:
    void insertKey(Key key) {
        // ...
    };  

    void insertKey(Key key) requires Smart<Key> = delete;

};

Get hands-on with 1400+ tech skills courses.