/** * @file * @brief 継承ツリーにタグ番号取得機能を付加し、それに基づくディスパッチ処理を実現するための型や関数を含むファイルです。 * @author AKIYAMA Kouhei * @since 2012-04-19 * * 使用例: * @code * struct Base : tagged_object::TaggedBase * { * struct DerivedTypes; * bool b; * explicit Base(bool b) : b(b){} * }; * * struct D1 : tagged_object::TaggedDerived * { * int i; * D1(int i, bool b) : TaggedDerived(b), i(i){} * }; * * struct TAGGED_DERIVED(D2, Base) //D2を二カ所書くのが気に入らなければTAGGED_DERIVEDマクロが使えます。 * { * double d; * D1(double d, bool b) : TaggedDerived(b), d(d){} * }; * * struct Base::DerivedTypes * { * typedef boost::mpl::list< * D1, * D2 * > Types; * }; * * * struct Printer * { * double operator()(const D1 &d1){ std::cout << "D1 " << d1.i << std::endl; return d1.i;} * double operator()(const D2 &d2){ std::cout << "D2 " << d2.d << std::endl; return d2.d;} * }; * Base *pb = new D2(3.14, true); * const double result = dispatch(Printer(), *pb); * @endcode */ #ifndef TAGGED_OBJECT_H_INCLUDED_20120419 #define TAGGED_OBJECT_H_INCLUDED_20120419 #include #include #include #include #include #include #include #include "boost/mpl/bool.hpp" #include "boost/mpl/transform.hpp" namespace tagged_object{ /** * タグ付きオブジェクトの実装を助ける基底クラスです。 */ template struct TaggedBase { virtual ~TaggedBase(){} virtual int get_tag() const = 0; }; /** * タグ付きオブジェクトの派生クラスの実装を助ける基底クラスです。 */ template struct TaggedDerived : Base { TaggedDerived() : Base(){} template explicit TaggedDerived(const T0 &a0) : Base(a0){} template explicit TaggedDerived(const T0 &a0, const T1 &a1) : Base(a0, a1){} template explicit TaggedDerived(const T0 &a0, const T1 &a1, const T2 &a2) : Base(a0, a1, a2){} virtual int get_tag() const { return boost::mpl::index_of::type::value; } }; #define TAGGED_DERIVED(D, B) D : tagged_object::TaggedDerived // --------------------------------------------------------------------------- // Dispatcher // --------------------------------------------------------------------------- template struct TaggedInvoker { static Result call(Fun &f, ArgPtr a) { return invoke(f, a, boost::mpl::bool_<(Index < boost::mpl::size::value)>()); } static Result invoke(Fun &f, ArgPtr a, boost::mpl::false_) { throw std::out_of_range("index out of range in TaggedInvoker."); //return Result(); //requires default constructor. } template static Result invoke(Fun &f, Arg *a, boost::mpl::true_) { typedef typename boost::mpl::at_c::type Derived; return f(*static_cast(a)); } template static Result invoke(Fun &f, const Arg *a, boost::mpl::true_) { typedef typename boost::mpl::at_c::type Derived; return f(*static_cast(a)); } template static Result invoke(Fun &f, const boost::shared_ptr &a, boost::mpl::true_) { typedef typename boost::mpl::at_c::type Derived; return f(boost::dynamic_pointer_cast(a)); } template static Result invoke(Fun &f, const boost::shared_ptr &a, boost::mpl::true_) { typedef typename boost::mpl::at_c::type Derived; return f(boost::dynamic_pointer_cast(a)); } }; template Result dispatch(Fun &f, ArgPtr a, int argtype) { if(!a){ throw std::invalid_argument("argument is NULL."); } BOOST_STATIC_ASSERT(boost::mpl::size::value <= 20); switch(argtype){ case 0: return TaggedInvoker::call(f, a); case 1: return TaggedInvoker::call(f, a); case 2: return TaggedInvoker::call(f, a); case 3: return TaggedInvoker::call(f, a); case 4: return TaggedInvoker::call(f, a); case 5: return TaggedInvoker::call(f, a); case 6: return TaggedInvoker::call(f, a); case 7: return TaggedInvoker::call(f, a); case 8: return TaggedInvoker::call(f, a); case 9: return TaggedInvoker::call(f, a); case 10: return TaggedInvoker::call(f, a); case 11: return TaggedInvoker::call(f, a); case 12: return TaggedInvoker::call(f, a); case 13: return TaggedInvoker::call(f, a); case 14: return TaggedInvoker::call(f, a); case 15: return TaggedInvoker::call(f, a); case 16: return TaggedInvoker::call(f, a); case 17: return TaggedInvoker::call(f, a); case 18: return TaggedInvoker::call(f, a); case 19: return TaggedInvoker::call(f, a); } assert(argtype >= 0 && argtype < 19); throw std::out_of_range("argtype out of range."); } // reference template inline Result dispatch(Fun &f, Base &a) { return dispatch(f, &a, a.get_tag()); } template inline Result dispatch(const Fun &f, Base &a) { return dispatch(f, &a, a.get_tag()); } template inline Result dispatch(Fun &f, const Base &a) { return dispatch(f, &a, a.get_tag()); } template inline Result dispatch(const Fun &f, const Base &a) { return dispatch(f, &a, a.get_tag()); } // shared_ptr template inline Result dispatch(Fun &f, const boost::shared_ptr &a) { return dispatch(f, a, a ? a->get_tag() : -1); } template inline Result dispatch(const Fun &f, const boost::shared_ptr &a) { return dispatch(f, a, a ? a->get_tag() : -1); } template inline Result dispatch(Fun &f, const boost::shared_ptr &a) { return dispatch(f, a, a ? a->get_tag() : -1); } template inline Result dispatch(const Fun &f, const boost::shared_ptr &a) { return dispatch(f, a, a ? a->get_tag() : -1); } }//namespace tagged_object #endif