/**
* @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