Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is emulating pure virtual function in static polymorphism using CRTP possible?

I'm trying to implement compile-time polymorphism using CRTP, and want to force the derived class to implement the function.

The current implementation is like this.

template <class Derived>
struct base {
    void f() {
        static_cast<Derived*>(this)->f();
    }
};

struct derived : base<derived>
{
    void f() {
    ...
    }
};

In this implementation, call to the function falls into an infinite loop if the derived class didn't implement f().

How do I force the derived class to implement the function like pure virtual function? I tried to use 'static_assert' like static_assert(&base::f != &Derived::f, "...") but it generates an error message saying that two member function pointers pointing to the different classes' member functions are not comparable.

like image 956
Inbae Jeong Avatar asked Feb 09 '15 05:02

Inbae Jeong


People also ask

Can a pure virtual function be static?

A virtual function cannot be global or static because, by definition, a virtual function is a member function of a base class and relies on a specific object to determine which implementation of the function is called. You can declare a virtual function to be a friend of another class.

Can we override pure virtual function?

A pure virtual function is a function that must be overridden in a derived class and need not be defined. A virtual function is declared to be “pure” using the curious =0 syntax. For example: class Base {

Does virtual function come under polymorphism?

A virtual function is a special type of function that, when called, resolves to the most-derived version of the function that exists between the base and derived class. This capability is known as polymorphism.

Is Crtp faster?

CRTP is faster because there is no virtual function call overhead and it compiles to smaller code because no type information is generated.


2 Answers

You can give the thing you override and the hook different names, like this:

template <class Derived>
struct base {
    void f() {
        static_cast<Derived*>(this)->fimpl();
    }
    void fimpl() = delete;
};

struct derived : base<derived> {
    void fimpl() { printf("hello world\n"); }
};

Here, fimpl = delete in the base so that it cannot be called accidentally unless fimpl is overridden in the derived class.

You can also stick an intermediate hiding layer into your CRTP to "temporarily" mark f as delete:

template <class Derived>
struct base {
    void f() {
        static_cast<Derived*>(this)->f();
    }
};

template <class Derived>
struct intermediate : base<Derived> {
    void f() = delete;
};

struct derived : intermediate<derived> {
    void f() { printf("hello world\n"); }
};
like image 147
tmyklebu Avatar answered Sep 18 '22 23:09

tmyklebu


template<typename Derived>
class Base
{
  private:
    static void verify(void (Derived::*)()) {}

  public:
    void f()
    {
        verify(&Derived::f);
        static_cast<Derived*>(this)->f();
    }
};

If the derived class does not implement f on its own, the type of &Derived::f would be void (Base::*)(), which breaks compilation.

Since C++11 we can also make this function generic with variadic template.

template<typename Derived>
class Base
{
  private:
    template<typename T, typename...Args>
    static void verify(T (Derived::*)(Args...)) {}
};
like image 21
jdh8 Avatar answered Sep 18 '22 23:09

jdh8