Subsumption and Negations

Get an overview of the subsumptions and negations.

Do subsumptions and negations matter?

Subsumptions and negations matter when there are multiple versions of the same method differentiated only by their constraints. Then, the compiler has to look for the most constrained version. Let’s assume that we have a class Ignition with two versions of the start method:

template <typename Key>
class Ignition {
public:
    void start(Key key) requires (!Smart<Key>) {}

    void start(Key key) requires (!Smart<Key>) && Personal<Key> {}
};

The compiler uses boolean algebra to find the most constrained version of start(). This process is called subsumption.

If we call Ignition with a Key that is not Smart, we expect the compiler to subsume that the first constraints of the two overloads of Ignition::start() are common. We have to check whether the second one applies to our Key type or not.

It may seem simple, but appearances can be deceiving!

If we call Ignition::start() with a Key that is not Smart and compile the code, we will get an error message that complains about an ambiguous overload.

Where is the problem?

The problem is that the () is part of the expression. When it comes to subsumption, the compiler checks the source location of the expression. The compiler can only subsume them if they originate from the same space.

Get hands-on with 1200+ tech skills courses.