CRTP避免动态多态

88 c++ virtual templates crtp

如何在C++中使用CRTP来避免虚拟成员函数的开销?

Dea*_*ael 136

有两种方法.

第一个是通过静态为类型结构指定接口:

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.
};
Run Code Online (Sandbox Code Playgroud)

第二个是避免使用引用到基础或指针到基础的习惯用法并在编译时进行连接.使用上面的定义,您可以使用如下所示的模板函数:

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
Run Code Online (Sandbox Code Playgroud)

因此,在函数中结合结构/接口定义和编译时类型推导允许您进行静态调度而不是动态调度.这是静态多态的本质.

  • 很好的答案 (15认同)
  • 我想强调一下,'not_derived_from_base`不是从`base`派生出来的,也不是从`base`派生出来的...... (5认同)
  • 实际上,my_type/your_type中的foo()声明不是必需的.codepad.org/ylpEm1up(导致堆栈溢出) - 有没有办法在编译时强制执行foo的定义? - 好的,找到了一个解决方案:ideone.com/C6Oz9 - 也许你想在你的答案中纠正这个问题. (3认同)
  • 你能解释一下在这个例子中使用CRTP的动机是什么吗?如果bar将被定义为模板<class T> void bar(T&obj){obj.foo(); 那么提供foo的任何类都没问题.因此,根据您的示例,看起来CRTP的唯一用途是在编译时指定接口.那是什么意思? (3认同)

fiz*_*zer 18

我一直在寻找CRTP的正确讨论.托德Veldhuizen的科学的C++技术是一个很好的资源(1.3)等诸多先进技术,如表情模板.

另外,我发现你可以在Google书籍上阅读Coplien的大部分原创C++ Gems文章.也许情况仍然如此.


Rog*_*mbe 1

我不得不查找CRTP。然而,完成此操作后,我发现了一些有关静态多态性的内容。我怀疑这就是你问题的答案。

事实证明,ATL相当广泛地使用了这种模式。