downcast overloading.에서 언급했던 downcast overloading 테크닉?을 유틸리티처럼 빼서 구현해보았습니다.
실제로 돌려보려면, boost 1.33.1 이상이 필요합니다. 구현 및 테스트는 VC7.1(VS2003)에서 했습니다. 하핫.
다운로드는 여기에서 하시면 됩니다.
그럼 실제로 코드를 봅시다.
template <class TL, typename executor>
struct downcast_overloader
{
typedef TL downcast_typelist;
executor exec_;
downcast_overloader(executor exec)
: exec_(exec)
{
}
template <class T>
void operator()(T* obj)
{
process_<downcast_typelist>(obj, boost::mpl::bool_<false>());
}
private:
template <class TL, class T>
void process_(T* obj, boost::mpl::bool_<false>)
{
typedef boost::mpl::front<tl>::type current_type;
typedef boost::mpl::pop_front<tl>::type next_list;
current_type* current_obj = dynamic_cast<current_type*>(obj);
if(current_obj != 0)
{
exec_(current_obj);
}
else
{
process_<next_list>(
obj,
boost::mpl::bool_<boost::mpl::empty<next_list>::value>::type()
);
}
}
template <class TL, class T>
void process_(T* obj, boost::mpl::bool_<true>){}
};
기본적인 사항은 전에 언급한 바와 동일합니다만, 실행될 함수를 exec_로 빼둔 것이 다른 점이지요. 그리고, 이 로직을 바깥으로 빼냄으로써 원 클래스에 수정을 가하지 않고도 downcast overloading이 가능해졌다는 점입니다.
operator()를 구현한 호출가능 객체를 이용하는 예를 봅시다.
void test_it(A* obj){...}
void test_it(B* obj){...}
void test_it(C* obj){...}
struct test_func
{
template <class T>
void operator()(T* obj)
{
test_it(obj);
}
};
void test()
{
typedef boost::mpl::vector<a, B, C> test_types;
test_func tf;
downcast_overloader<test_types, test_func> overloader(tf);
A a;
B b;
overloader(&a);
}
템플릿으로 된 함수를 넘기는 법을 몰라서(불가능한듯??), 그냥 템플릿 함수를 쓰는 버젼은 생각 안했습니다. 하아; 그냥 함수 오버로딩으로 된 코드를 호출하기 위해 wrapper를 쓰는 게지요.
여기서는 test_func 구조체가 size가 0이므로 크게 상관이 없습니다만, 크기가 존재하는 클래스라면 다음과 같은 코드가 필요할 겁니다.
void test()
{
typedef boost::mpl::vector<a, B, C> test_types;
test_func tf;
downcast_overloader<test_types, test_func&> overloader(tf);
A a;
B b;
overloader(&a);
}
이렇게 작성해놓고 보니 뭔가 불편하군요. downcast_overload
template <class TL, class executor, class T>
void downcast_overload(executor exec, T* obj)
{
downcast_overloader<tl, executor> overloader(exec);
overloader(obj);
}
template <class TL, class executor, class T>
void downcast_overload_ref(executor& exec, T* obj)
{
downcast_overloader<tl, executor&> overloader(exec);
overloader(obj);
}
downcast_overload_ref는 reference를 받는 버젼이고, downcast_overload는 값을 받는 버젼입니다.
+ 리턴타입과 Parameter를 여러개 쓰는 버젼을 만들고 싶었지만… 귀찮기도 하고 시간도 없고.. T_T
“downcast_overloader 코드. :)”의 한가지 생각