CRTP to avoid dynamic polymorphism

五迷三道 提交于 2019-12-17 02:52:36

问题


How can I use CRTP in C++ to avoid the overhead of virtual member functions?


回答1:


There are two ways.

The first one is by specifying the interface statically for the structure of types:

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

struct my_type : base<my_type> {
  void foo(); // required to compile.
};

struct your_type : base<your_type> {
  void foo(); // required to compile.
};

The second one is by avoiding the use of the reference-to-base or pointer-to-base idiom and do the wiring at compile-time. Using the above definition, you can have template functions that look like these:

template <class T> // T is deduced at compile-time
void bar(base<T> & obj) {
  obj.foo(); // will do static dispatch
}

struct not_derived_from_base { }; // notice, not derived from base

// ...
my_type my_instance;
your_type your_instance;
not_derived_from_base invalid_instance;
bar(my_instance); // will call my_instance.foo()
bar(your_instance); // will call your_instance.foo()
bar(invalid_instance); // compile error, cannot deduce correct overload

So combining the structure/interface definition and the compile-time type deduction in your functions allows you to do static dispatch instead of dynamic dispatch. This is the essence of static polymorphism.




回答2:


I've been looking for decent discussions of CRTP myself. Todd Veldhuizen's Techniques for Scientific C++ is a great resource for this (1.3) and many other advanced techniques like expression templates.

Also, I found that you could read most of Coplien's original C++ Gems article at Google books. Maybe that's still the case.




回答3:


I had to look up CRTP. Having done that, however, I found some stuff about Static Polymorphism. I suspect that this is the answer to your question.

It turns out that ATL uses this pattern quite extensively.




回答4:


This Wikipedia answer has all you need. Namely:

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

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

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

Although I don't know how much this actually buys you. The overhead of a virtual function call is (compiler dependent, of course):

  • Memory: One function pointer per virtual function
  • Runtime: One function pointer call

While the overhead of CRTP static polymorphism is:

  • Memory: Duplication of Base per template instantiation
  • Runtime: One function pointer call + whatever static_cast is doing


来源:https://stackoverflow.com/questions/262254/crtp-to-avoid-dynamic-polymorphism

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!