一汁三菜

自分が楽しいと思うこと、マラソン、旅行、その他日々の記録をしたい。

CRTP

template<class Derived>
class base {};

class Foo : public base<Foo> {};

という風に、テンプレートクラスを継承して、テンプレート引数にクラス自身を適用するようなtemplateの使い方の事を、CRTP (Curiously Recursive Template Pattern) と言うそうな。

こうすると基底クラスが派生クラスの事を知る事が出来るようになるので、それを使って色々と面白い事が出来ますよという。

例えば、operator==()が定義されているクラスにoperator!=()を定義するクラスNegatorは、次の通り。

#include <iostream>
#include <cmath>

template <class T>
class Negator {
  friend bool operator!=(const T &x, const T &y) {
    return !x.operator==(y);
  }
};

(例として適切かどうかはともかく)2次元平面の距離を求めるクラスを以下のように作ります。Plotクラスにはoperator==()しか定義されていませんが、Negatorクラスを継承する事によって、operator!=(const Plot &x, const Plot &y)が定義されます。

class Plot : public Negator<Plot> {
  int x, y;
public:

  Plot(int x_, int y_) { x = x_; y = y_; }
  bool operator==(const Plot &a) const {
    double d1 = x * x + y * y;
    double d2 = a.x * a.x + a.y * a.y;
    return fabs(d1 - d2) < 1e-6;
  }
};

利用例は以下の通り。

int main(void)
{
  Plot p1(10, 20);
  Plot p2(20, 10);

  if(p1 == p2) std::cout << "equal" << std::endl;
  if(p1 != p2) std::cout << "not equal" << std::endl;

  return 0;
}