[C++プログラミング手法]
型ごとの番号付け
2009/01/12_181416意図
動的に、型ごとに番号付けをする。
動機
C++では、動的に型の独自性をチェックする場合はtype_infoクラスを使用する。 type_infoはtypeid 演算子を使用することで取得することができる。type_infoは順序付けされており、比較演算子などで比較することで、同じクラスかどうかを比較することができる。
しかし、type_infoは整数としては扱えないため、配列のインデックスアクセスなどでは使用できない。また、プログラム中で同じ比較しかできないため、指定した順番にしたいなどの要求に応えることはできない。
解法とサンプルコード
小粋なカウンタ(Nifty_Counter)、及びテンプレート関数、静的局所変数を組み合わせて、型からunsigned intへの変換を実現する。
// Numbering.hpp template<typename derived_t> class Numbering { public: template<typename type_t> static unsigned int number() { static unsigned int r(count()); return r; }; private: static unsigned int count() { static unsigned int r(0); return r++; }; }; // main.cpp class A : public Numbering<A> {}; class B : public Numbering<B> {}; int main() { A::number<int>(); //0 ……(1) A::number<int*>(); //1 A::number<int&>(); //2 A::number<const int>(); //3 A::number<const int*>(); //4 A::number<const int&>(); //5 A::number<int>(); //0 ……(2) A::number<int*>(); //1 A::number<int&>(); //2 A::number<const int>(); //3 A::number<const int*>(); //4 A::number<const int&>(); //5 B::number<const int&>(); //0 B::number<const int*>(); //1 B::number<const int>(); //2 B::number<int>(); //3 B::number<int*>(); //4 B::number<int&>(); //5 B::number<const int&>(); //0 B::number<const int*>(); //1 B::number<const int>(); //2 B::number<int>(); //3 B::number<int*>(); //4 B::number<int&>(); //5 };
Numberingテンプレートが指定された型ごとにナンバリングを行うテンプレートである。 ここでは汎用性を高めるため奇妙に再帰したテンプレートとしている。
Numberingは静的テンプレートメンバ関数numberを持つ。numberは型ごとに異なった関数を実体化する。また、numberは関数内に静的局所変数rを持つ。
静的局所変数は、コンパイル時に判別可能な定数を指定されていない場合は、その関数が実行される時に初期化される。すなわち、上記例の(1)のように、各々の型ごとのメンバ関数が初めて実行される時に初期化される。
静的局所変数rは、静的メンバ関数countからの戻り値で初期化される。静的メンバ関数countは呼び出されるごとにインクリメントされた別の整数を返すので、rにはそれぞれの型ごとに別々の整数が割り当てられる。
また、以前に指定された型でnumberが呼び出された場合(2)は、rは既に初期化済のためcountは実行されず、すでに割り当てられたrの値をそのまま返す。
この結果、Numberは型ごとに異なった整数を返すことができる。
制作・著作: 野分(nowake) at fiercewinds.net (Creative Commons 表示-継承 2.1 日本)