downcast_overloader 코드. :)

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(tf, obj) 와 같은 형태로 쓸 수 있다면 편할텐데요. 네. 가능합니다.

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

글쓴이: crowmania

Chief Developer in Somansa Guitar/Vocal in Tonics Member of Justice Party

“downcast_overloader 코드. :)”의 한가지 생각

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다