汎用関数オブジェクトのためのパラメータ(2)
IParameter はこんな感じに定義しておけばいいだろう。
class _IParameter { public: virtual _IParameter() { } }; typedef boost::shared_ptr<_IParameter> IParameter;
で、引数に取る型は全て内部的に _IParameter を継承するようにして、
T GetParameter<T>(IParameter parameter) { // これは擬似コード。 // 実際にはこんな簡単にはいかないはず……。 boost::shared_ptr<T> p = dynamic_pointer_cast<T>(parameter); if (p == null) throw std::bad_cast(); return *p; }
こんな感じで dynamic_cast<> を使って取得できればいいなぁと思うわけだ。
でも int やら void* やらを dynamic_cast<> することは不可能なので、これらは別扱いをする必要があったりとかで結構複雑になりそう。
例えばパラメータの型が int とかの仮想テーブルを持っていない型だった場合は、
template<class T> struct ValueParameter : public _IParameter { T value; }; // T は基本型 template<class T> IParameter MakeParameter(T value) { return boost::shared_ptr<ValueParameter<T>>(new ValueParameter<T>(value)); } template<class T> T GetParameter(IParameter parameter) { boost::shared_ptr<ValueParameter<T>> p = dynamic_pointer_cast<ValueParameter<T>>(parameter); if (p == null) throw std::bad_cast(); return (*p).value; }
こうやって格納する。これで int とかの型を IParameter 型に置き換えることが出来る。
同じように仮想テーブルを持っている型だった場合は、
template<class T> struct ClassParameter : public _IParameter, public T { ClassParameter(T value) : T(value) { } }; // T はクラスまたは構造体 template<class T> IParameter MakeParameter(T value) { return boost::shared_ptr<ClassParameter<T>>(new ClassParameter<T>(value)); } template<class T> T GetParameter(IParameter parameter) { boost::shared_ptr<ClassParameter<T>> p = dynamic_pointer_cast<ClassParameter<T>>(parameter); if (p == null) throw std::bad_cast(); return *p; }
こうやって、ClassParameter が T を継承することによって、IParameter 型に置き換えられるようにする。
しかもこれだと _IParameter 型が仮想テーブルを持っているので、仮想テーブルを持っていないクラスでも IParameter 型にキャストすることが出来るようになる。
……で、ここまで考えて気が付いたんだけど、これってポインタ型が全く考慮されてないんですよね。
例えば仮想テーブルを持ったクラスへのポインタ(例えば CWnd*)を上位(CObject*)にキャストして取り出すとかそういうことが出来ないと話にならないので、そこを何とかしないとダメなようです。
しかし CWnd* は仮想テーブルを持っているけれども、_IParameter を継承しているわけではないので、IParameter 型に置き換えることが出来ない。
新しく値をコピーするわけにもいかないし、
class dynamic_cast_tag { }; template<class T> class PointerParameter : public _IParameter { public: T value; template<class U> PointerParameter(const PointerParameter<U>& p, dynamic_cast_tag) { value = dynamic_cast<T>(p.value); } }; // T は仮想テーブルを持ったクラスへのポインタ template<class T> IParameter MakeParameter(T value) { return boost::shared_ptr<PointerParameter<T>>(new PointerParameter<T>(value)); }
こうやって書いたとしても、
template<class T> T GetParameter(IParameter parameter) { // これは間違い boost::shared_ptr<PointerParameter<T>> p = dynamic_pointer_cast<PointerParameter<T>>(parameter); ... }
PointerParameter::PointerParameter<>() の中で dynamic_cast<> を行おうとしているが、例えば PointerParameter
うーん……どうするべきか……。