Chained Inheritance(鎖状継承とでも訳すべきですかね?)

以下のようなクラス群を考えます.

class nil_t{};

template
class A : public Super
{ };

template
class B : public Super
{ };

template
class C : public Super
{ };

Aのテンプレート引数T1とT2,Bのテンプレート引数T,Cのテンプレート引数T1とT2は各々のクラスに必要なテンプレート引数だと思ってください.上のA,B,Cに共通する事としてテンプレート引数で自身の親クラスを指定できるということが挙げられます.また,そのデフォルトはnil_tという空のクラスに指定されています.
さて,クラスDをクラスCから継承してみます.

class D : public C
{ };

何の問題も無いですね?一つだけ,Cが暗黙のうちにnil_tから継承されているということには注意が必要です.
さて,では以下のように書くとどうなるでしょうか?

class D
 : public C >
{ };

まず,Bは暗黙のうちにnil_tを継承しています.次にC >はBを継承しています.最後にDはそのC >を継承しています.要するに上のように書くことでnil_t → B → C → Dという継承の鎖を生成することが出来ます.
となれば,後は以下のように自由に継承の鎖を生成できるということは簡単に想像できるかと思います.

class D
 : public B > >
{ };

上の例ではnil_t → C → A → B → Dという継承の連鎖を生成しています.
このChained Inheritanceを利用する目的とその実例として,自分が知っている範囲内では

  • (インターフェースやポリシーを規定するような)空クラスを多数継承する際に,EBCOが効かない環境での空間のオーバーヘッドの削減を図る -> boost::operators
  • 継承によってクラスの構造(データメンバ)の構築を行う -> boost::property

あたりが挙げられるでしょうか?珍しいテクニックではあると思います.

浮動小数点演算回数計測クラス

浮動小数点演算(FLoating point Operation)の回数をカウントする以下のような非常に単純なクラスを作ってみました.

#include 
#include 

template<
  class Real = double,
  class Counter = long long>
class flo_counter
  : public
    boost::unit_steppable,
    boost::euclidian_ring_operators,
    boost::euclidian_ring_operators, Real,
    boost::partially_ordered,
    boost::partially_ordered, Real
    > > > > >
{
public:
  flo_counter(Real const &r = Real())
    : val(r)
  { }

  flo_counter(flo_counter const &r)
    : val(r.val)
  { }

  flo_counter &operator++()
  { return ++val; }

  flo_counter &operator--()
  { return --val; }

#define DEFINE_ASSIGNMENT_OPERATOR(OP)                                        \
flo_counter & operator ## OP(flo_counter const &rhs)                          \
{                                                                             \
  val OP rhs.val;                                                             \
  ++cnt;                                                                      \
  return *this;                                                               \
}                                                                             \

#define DEFINE_ASSIGNMENT_OPERATOR2(OP)                                       \
flo_counter & operator ## OP(Real const &rhs)                                 \
{                                                                             \
  val OP rhs;                                                                 \
  ++cnt;                                                                      \
  return *this;                                                               \
}                                                                             \

  DEFINE_ASSIGNMENT_OPERATOR(+=)
  DEFINE_ASSIGNMENT_OPERATOR(-=)
  DEFINE_ASSIGNMENT_OPERATOR(*=)
  DEFINE_ASSIGNMENT_OPERATOR(/=)
  DEFINE_ASSIGNMENT_OPERATOR(%=)

  DEFINE_ASSIGNMENT_OPERATOR2(+=)
  DEFINE_ASSIGNMENT_OPERATOR2(-=)
  DEFINE_ASSIGNMENT_OPERATOR2(*=)
  DEFINE_ASSIGNMENT_OPERATOR2(/=)
  DEFINE_ASSIGNMENT_OPERATOR2(%=)

#undef DEFINE_ASSIGNMENT_OPERATOR
#undef DEFINE_ASSIGNMENT_OPERATOR2

#define DEFINE_BOOLEAN_OPERATOR(OP)                                           \
bool operator ## OP(flo_counter const &rhs) const                             \
{                                                                             \
  return val OP rhs.val;                                                      \
}                                                                             \

#define DEFINE_BOOLEAN_OPERATOR2(OP)                                          \
bool operator ## OP(Real const &rhs) const                                    \
{                                                                             \
  return val OP rhs;                                                          \
}                                                                             \

  DEFINE_BOOLEAN_OPERATOR(<)
  DEFINE_BOOLEAN_OPERATOR(==)

  DEFINE_BOOLEAN_OPERATOR2(<)
  DEFINE_BOOLEAN_OPERATOR2(>)
  DEFINE_BOOLEAN_OPERATOR2(==)

#undef DEFINE_BOOLEAN_OPERATOR
#undef DEFINE_BOOLEAN_OPERATOR2

  flo_counter sqrt() const
  { return flo_counter(std::sqrt(val)); }

  flo_counter abs() const
  { return flo_counter(std::abs(val)); }

  static Counter &count()
  { return cnt; }

private:
  Real val;
  static Counter cnt;
};

template
Counter flo_counter::cnt = 0;

sqrtやabsのようなあまり本質的でないメンバ関数が入ってますがあまり気にしないでください.このクラスで一番目立つのは継承の部分でしょうか?Boost.Operatorsの枠組みに従うと必然的にこうなります.この継承の部分はよく見れば分かりますが,CRTPとChained Inheritanceの複合技です.Boost.OperatorsがCRTPで何をしているかについてはid:Cryolite:20040605#p2あたりを参考にしてみてください.
上のflo_counterはこれで組み込みの浮動小数点型とほとんど同等なものとして振舞うことが可能になります.でもこれだけでは全然面白くないので,次回はこれをboost::numeric::ublas::vectorあたりにでも突っ込んでみようかと思います.