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 코드. :)”의 한가지 생각