When to use CRTP over explicit object parameter in c++23?

363 views Asked by At

Short Version of Question

C++23 gives us a new way to write mixin classes (instead of CRTP). Is there any context where CRTP would still be preferred?

Summary of the Two Approaches

CRTP is a powerful idiom in C++ that leverages templates to automatically generate type-specific behavior at runtime. This is often used to create mixin classes.

C++23 introduces explicit object parameters, which allow the class name to be referenced explicitly in the parameter lists of non-static member functions. As a result, template non-static member functions can access the derived class, eliminating the need to specialize the mixin over the derived class.

Here is an example illustrating the old and new approach.

// classic CRTP (old approach)
template <typename T>
class MyMixin<T> {
    // ...
    void foo() {
        // Stuff using T...
    }
};

// have to specialize MyMixin over MyType
class MyType : public MyMixin<MyType> {
    // ...
};



// explicit object parameter (C++23 approach)
class MyMixin {
    // ...
    template <typename T>
    void foo(this T* self) {
        // Stuff using T...
    }
};

// better syntax for mixins
class MyType : public MyMixin {
    // ...
};

Clearly, the new approach leads to cleaner syntax in the derived class. For instance, it lets us avoid gnarly things like this:

template<typename x, typename y, typename z, typename w>
class MyWackyContainer : public MyMixin<MyWackyContainer<x,y,z,w>>

since we don't have to provide a template parameter to MyMixin with the new approach.

Full Question

Per the abstract of this paper (which addresses the previously mentioned problem),

While [adding explicit object parameters] has removed the need for using CRTP in many places, there still exist cases that must be expressed using this pattern.

The only functional difference I could think of between CRTP and the new approach, is that CRTP would let us reference the type when declaring non-function members and static member functions. But is there any situation where this is actually useful?

(Secondary question: Is my understanding correct? Did I miss anything?)

2

There are 2 answers

0
jwezorek On

The big difference is that the CRTP base classes are distinct types, for which there is no equivalent type in the explicit object parameter version. Those types can be useful.

The static member thing is one example. The fact that you have distinct types allows you to implement static members that are only shared within a single derived class and not between all of them.

But also you may just need those types for whatever, as a place to put type alias definitions for example.

0
Jarod42 On

From https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p0847r7.html#proposed-syntax

Member functions with an explicit object parameter cannot be static or virtual and they cannot have cv- or ref-qualifiers.

So CRTP is still the only way for virtual and static functions.