TypeErasure で元の型にキャストする
Boost.TypeErasure で処理を呼び出す際に元の型にキャストして渡しています。
template<class C, class T> struct push_back { static void apply(C& cont, const T& arg) { cont.push_back(arg); } }; std::vector<int> vec; any<push_back<_self, int>, _self&> c(vec); int i = 10; call(push_back<_self, int>(), c, i); // push_back::apply(std::vector<int>, int) が呼ばれる
これの仕組みがよく分からなくて、Boost.TypeErasure のソースを読んでいたんですが、多分こんな感じじゃないのかなーと。
[ソース]
#include <iostream> #include <boost/any.hpp> template<typename Concept, typename T> struct adapter{ static void apply(boost::any const& any){ Concept::apply(boost::any_cast<T>(any)); } }; template<typename Concept> struct any{ typedef void(*applicative_type)(boost::any const&); template<typename T> any(T const& t) : data(t) , applicative(&adapter<Concept, T>::apply) {} void apply(){ applicative(data); } private: boost::any data; applicative_type applicative; }; struct ostreamable{ template<typename T> static void apply(T const& t){ std::cout << typeid(t).name() << std::endl; std::cout << t << std::endl; } }; struct functionable{ template<typename T> static void apply(T const& t){ std::cout << typeid(t).name() << std::endl; t(); } }; struct X{ X(int value) : value(value){} void operator ()() const{ std::cout << value << std::endl; } int value; }; std::ostream& operator <<(std::ostream& os, X const& x){ return os << x.value; } int main(){ any<ostreamable> i = 10; i.apply(); X x = 42; any<ostreamable> x_any = x; x_any.apply(); any<functionable> func = [](){ std::cout << "homu" << std::endl; }; func.apply(); any<functionable> x_func = x; x_func.apply(); return 0; }
[出力]
int 10 struct X 42 class `anonymous namespace'::<lambda0> homu struct X 42
adapter が Boost.Any から元の型へとキャストを行い処理を呼び出し、その static メンバ関数ポインタを any が保持しています。
Boost.TypeErasure の場合は複数の Concept や引数に対応しているのでもっとメタメタしていますが、だいたいこんな感じで実装されているんじゃないでしょうか。
実際に書いてみるとそんなに難しい事はしていないですね。
すっきりしすぎているので逆にどこか( More C++ Idioms 辺りにでも)載っているんじゃないだろうか。
2日ぐらいずーっとソース読んでいたけど全然気づかなかった…。