Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Confusion about CRTP static polymorphism

Tags:

c++

crtp

I'm trying to wrap my head around the CRTP. There are some good sources around, including this forum, but I think I have some confusion about the basics of static polymorphism. Looking at the following Wikipedia entry:

template <class T> 
struct Base
{
    void implementation()
    {
        // ...
        static_cast<T*>(this)->implementation();
        // ...
    }

    static void static_func()
    {
        // ...
        T::static_sub_func();
        // ...
    }
};

struct Derived : public Base<Derived>
{
    void implementation();
    static void static_sub_func();
};

I understand that this helps me to have different implementation() variants in derived classes, kinda like a compile-time virtual function. However, my confusion is that I think I cannot have functions like

void func(Base x){
    x.implementation();
}

as I would with normal inheritance and virtual functions, due to Base being templated, but I would have to either specify

func(Derived x)

or use

template<class T> 
func(T x)

So what does CRTP actually buy me in this context, as opposed to simply shadowing/implementing the method straightforward in Derived::Base?

struct Base
{
    void implementation();
};

struct Derived : public Base
{
    void implementation();
    static void static_sub_func();
};
like image 631
user32849 Avatar asked May 06 '17 14:05

user32849


People also ask

What is the use of CRTP?

When using polymorphism, one sometimes needs to create copies of objects by the base class pointer. A commonly used idiom for this is adding a virtual clone function that is defined in every derived class. The CRTP can be used to avoid having to duplicate that function or other similar functions in every derived class.

Why use static polymorphism?

The static polymorphism should be used where there is no change of behaviour after compile-time. Therefore, if the code is an app that is compiled once and given to end-users to just run it, then, it is quite challenging to find a good place for static polymorphism.

What is static polymorphism?

Static Polymorphism is the linking of a function with an object during compile time is called static. It is also called static binding. C# provides two techniques to implement static polymorphism i.e. Function overloading and Operator overloading. Let us learn about Function Overloading.

Is Crtp faster?

As expected, the CRTP approach is much faster.


1 Answers

The thing is that the description of CRTP as "static polymorphism" is not really helpful or accurate, with regards to what CRPT is actually used for. Polymorphism is really just about having different types that fulfill the same interface or contract; how those different types implement that interface is orthogonal to polymorphism. Dynamic polymorphism looks like this:

void foo(Animal& a) { a.make_sound();  } //  could bark, meow, etc

Where Animal is a base class providing a virtual make_sound method, that Dog, Cat, etc, override. Here is static polymorphism:

template <class T>
void foo(T& a) { a.make_sound(); }

And that's it. You can call the static version of foo on any type that happens to define a make_sound method, without inheriting from a base class. And the call will be resolved at compile time (i.e. you won't pay for a vtable call).

So where does CRTP fit in? CRTP is really not about interface at all, so it's not about polymorphism. CRTP is about letting you implement things more easily. What makes CRTP magical is that it can inject things directly into the interface of a type, with full knowledge of everything the derived type provides. A simple example might be:

template <class T>
struct MakeDouble {
    T double() {
        auto& me = static_cast<T&>(*this);
        return me + me;
};

Now any class that defines an addition operator, can also be given a double method:

class Matrix : MakeDouble<Matrix> ...

Matrix m;
auto m2 = m.double();

CRTP is all about aiding in implementation, not interface. So don't get too hung up about the fact that it's often referred to as "static polymorphism". If you want the real canonical example on what CRTP can be used for, consider Chapter 1 of Andrei Alexandrescu's Modern C++ design. Though, take it slow :-).

like image 129
Nir Friedman Avatar answered Sep 28 '22 16:09

Nir Friedman