web-dev-qa-db-ja.com

動的多型を回避するCRTP

仮想メンバー関数のオーバーヘッドを回避するために、C++でCRTPを使用するにはどうすればよいですか?

87
Amit

2つの方法があります。

1つ目は、型の構造に対してインターフェイスを静的に指定することです。

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.
};

2番目の方法は、ベースへの参照またはベースへのポインターイディオムの使用を回避し、コンパイル時に配線を行うことです。上記の定義を使用すると、次のようなテンプレート関数を使用できます。

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

したがって、関数で構造/インターフェース定義とコンパイル時の型推論を組み合わせると、動的ディスパッチではなく静的ディスパッチを実行できます。これが静的多型の本質です。

135
Dean Michael

私は自分でCRTPのきちんとした議論を探していました。 Todd Veldhuizenの Scientific C++のテクニック は、この(1.3)および式テンプレートのような他の多くの高度なテクニックのための素晴らしいリソースです。

また、GoogleブックでCoplienのオリジナルのC++ Gemsの記事のほとんどを読むことができることがわかりました。たぶんそれはそうです。

18
fizzer

調べる必要がありました [〜#〜] crtp [〜#〜] 。しかし、それを行った後、私は 静的多態性 についていくつかのものを見つけました。これがあなたの質問に対する答えだと思います。

[〜#〜] atl [〜#〜] はこのパターンを非常に広範囲に使用していることがわかりました。

1
Roger Lipscombe