C++ のテンプレート関数へのポインタ

ある文字列をキー、それに対するクラスを値とするような map なり何なりをあらかじめ作っておいて、入力値である文字列によって生成されるオブジェクトを決定したい、みたいな状況に遭遇しました。

if キー1 オブジェクト 1 生成、if キー 2 オブジェクト 2 生成、みたいな実装にすると、キーが増える度にこの実装も変更しないといけないのが嫌で、対応するクラスを作って map なりに 1 行追加するだけで良いようなコードにしたかったのです。

で、どないしたらええやろと考えた結果、以下みたいに実装してみました。

C++:
  1. #include <iostream>
  2. #include <string>
  3. #include <map>
  4.  
  5. class Base {
  6. public:
  7.     virtual void hello() = 0;
  8. };
  9.  
  10. class A : public Base {
  11. public:
  12.     A() {
  13.         cout <<"A Constructor" <<endl;
  14.     }
  15.     void hello() {
  16.         cout <<"I'm A" <<endl;
  17.     }
  18. };
  19.  
  20. class B : public Base {
  21. public:
  22.     B() {
  23.         cout <<"B Constructor" <<endl;
  24.     }
  25.     void hello() {
  26.         cout <<"I'm B" <<endl;
  27.     }
  28. };
  29.  
  30. template<class T>
  31. Base* create() {
  32.     return new T;
  33. }
  34.  
  35. int main(int argc, char* argv[]) {
  36.     typedef Base* (*CREATEFUNC)();
  37.  
  38.     map<string, CREATEFUNC> m;
  39.     m.insert(pair<string, CREATEFUNC>("A", &create<A>));
  40.     m.insert(pair<string, CREATEFUNC>("B", &create<B>));
  41.  
  42.     for (map<string, CREATEFUNC>::const_iterator cit = m.begin();
  43.          cit != m.end();
  44.          c++it) {
  45.         Base* p = (cit->second)();
  46.         p->hello();
  47.     }
  48.  
  49.     return 0;
  50. }

テンプレートで指定したクラスを new して返すだけの関数を作って、それへのポインタを map のメンバとすることで、イテレータで回しながら new していってます。Base クラスで load とか save とかを純粋仮想関数としておいて(上でいう hello ですね)、追加するクラスにその実装を強制しておけば良い感じ。

テンプレート関数へのポインタに関するページをあまり見つけられなかったので書いておきました。

(2006/11/03 追記)
http://forums.belution.com/ja/cpp/000/048/99.shtml を見つけました。


About this entry