boost pp 20091102_서진택
TRANSCRIPT
boost day07BOOST_PP
2009.11.02서진택 , [email protected]
발표순서
• 문제제기• BOOST_PP 를 이용한 해결
Techniques 자체반복 구현
• Q&A
2
문제제기
• 템플릿 프로그램을 할 경우 , 비슷한 패턴 의 코드를 되풀이 해서 작성해야 하는 상황 이 발생한다 .
– 델리게이트의 작성– 부분 특수화의 경우– 기타등등
3
비슷한 패턴이 반복되는 상황
가능한 해결책
1. 무시하고 되풀이되는 패턴을 되풀이 해서작성한다 .
2. 전처리기를 적절하게 활용한다 .3. BOOST_PP 를 활용한다 .
– Boost preprocessing library– 기계적으로 되풀이 되는 코드는 기계적으로 생
성하는 것이 마땅
5
2 번째 해결책 : 전처리기를 적절하게 활용한다 .
소스는 죽 ~ 이어집니다 .
BOOST_PP 를 이용한 해결
• 전처리기 기본• 매크로
– object-like macro• #define 식별자 치환 - 목록
– function-like macro• #define 식별자 (a0,a1,…,an-1) 치환 - 목록
• 매크로 인수– , ( )
• 매크로 인수– FOO( std::pair<int,long> ) // 인수 2 개– FOO({int x=1,y=2;return x+y;}) // 인수 2
개– FOO( (std::pair<int,long>) ) // 인수 1 개– FOO(({int x=1,y=2;return x+y;})) // 인수
1 개
9
, 를 전달할 때는 BOOST_PP_COMMA 를사용한다 .
Technique
18
template<int x> struct int_ { static int const value = x; typedef int_<x> type; typedef int value_type; operator int() const { return x; } };
struct none {};
template<typename T0=none, typename T1=none, typename T2=none> struct tiny_size : int_<3> {};
template<typename T0, typename T1> struct tiny_size<T0,T1,none> : int_<2> {};
template<typename T0> struct tiny_size<T0,none,none> : int_<1> {};
template<> struct tiny_size<none,none,none> : int_<0> {};
모든 타입 파라미터에 대해 부분 특수화를
구현해야 한다 .
예 ) tiny_size 의 작성
19
void main(){ std::cout << ods::tiny_size<int,int,int>::value << std::endl; std::cout << ods::tiny_size<int>::value << std::endl;//3//1// 계속하려면아무키나누르십시오 . . .}//main()
template<class T0, class T1, class T1>
#define n 3template<BOOST_PP_ENUM_PARAMS(n,
class T)>
20
21
struct none {};
template<typename T0=none, typename T1=none, typename T2=none> struct tiny_size : int_<3> {};
#define TINY_print(z, n, data) data
#define TINY_size(z, n, unused) \ template<BOOST_PP_ENUM_PARAMS(n, class T)> \ struct tiny_size< \ BOOST_PP_ENUM_PARAMS(n, T) \ BOOST_PP_COMMA_IF(n) \ BOOST_PP_ENUM( \ BOOST_PP_SUB(TINY_MAX_SIZE,n), TINY_print, none) \ > \ : int_<n> {};
BOOST_PP_REPEAT( TINY_MAX_SIZE, TINY_size, ~ )
#undef TINY_size#undef TINY_print
수평 되풀이로 구현한예
n 이 1 인 경우의 확장 template<typename T0> struct tiny_size<T0,none,none> : int_<1> {};
되풀이 방법
• 수평 되풀이– 전처리기 출력에서 같은 줄이 된다 .• 디버깅이 거의 불가능하다 .
• 수직되풀이– 지역반복
• 디버깅이 불편하다
– 파일반복• 사소한 코드 패턴에 대해 .hpp 파일을 만들어야 한
다 .– 자체반복 22
예 ) 멤버함수 템플릿의 특수화구현
KSystemState::PostStateEvent() 의 기존구현
23
24
class KSystemState{public: template<typename T> void _Push( const char* pszInEvent_, T inValue_ ) { std::cout << pszInEvent_ << ":" << inValue_ << std::endl; }//_Push()
template<typename T0> void PostStateEvent( const char* pszInEvent, T0 in0 ); template<typename T0, typename T1> void PostStateEvent( const char* pszInEvent, T0 in0, T1 in1 );};//class KSystemState
25
template<typename T0>void KSystemStateEvent::PostStateEvent( const char* pszInEvent, T0 in0 ){ _Push( pszInEvent, in0 );}
template<typename T0, typename T1>void KSystemStateEvent::PostStateEvent( const char* pszInEvent, T0 in0, T1 in1 ){ _Push( pszInEvent, in0 ); _Push( pszInEvent, in1 );}
26
KSystemStateEvent g_systemState;
void main(){ g_systemState.PostStateEvent( "Input", 0 ); g_systemState.PostStateEvent( "Output", 1, "dummy" );//Input:0//Output:1//Output:dummy// 계속하려면아무키나누르십시오 . . .}//main() 타입 인자를 2 개까지만 전달
할 수 있다 .
자체반복 구현
• 반복 구현을 한 파일안에 작성
27
28
#define POST_STATE_MAX_ARG 2
class KSystemStateEvent{public: template<typename T> void _Push( const char* pszInEvent_, T inValue_ ) { std::cout << pszInEvent_ << ":" << inValue_ << std::endl; }//_Push()
#define _POST_STATE_EVENT_TEMPLATE(z, n, unused) \ template<BOOST_PP_ENUM_PARAMS(n, typename T)> \ void PostStateEvent( const char* szInEvent_, BOOST_PP_ENUM_PARAMS( n, T ) );
BOOST_PP_REPEAT_FROM_TO( 1, BOOST_PP_ADD(POST_STATE_MAX_ARG,1), _POST_STATE_EVENT_TEMPLATE, ~ )
#undef _POST_STATE_EVENT_TEMPLATE};//class KSystemStateEvent
선언과 body 를 별도로 구현 .
먼전 선언 부분을 간단하게 구현한다 .
29
#ifndef BOOST_PP_IS_ITERATING
1) 반복을 호출하는 부분 작성
#else // #ifndef BOOST_PP_IS_ITERATING
2) 되풀이 되는 패턴을 제공하는 부분 작성
#endif // #ifndef BOOST_PP_IS_ITERATING
KSystemState.hpp 파일 작성
30
#ifndef _KSYSTEMSTATE_INL#define _KSYSTEMSTATE_INL
#include <boost/preprocessor/repetition.hpp> #include <boost/preprocessor/arithmetic/sub.hpp> #include <boost/preprocessor/punctuation/comma_if.hpp> #include <boost/preprocessor/iteration/iterate.hpp>
#define _POST_ARG(z, n, unused) BOOST_PP_CAT(T,n) BOOST_PP_CAT(In,n) #define _POST_PUSH(z, n, unused) _Push( pszInEvent, BOOST_PP_CAT(In,n) );
// generate specializations #define BOOST_PP_ITERATION_LIMITS (1, POST_STATE_MAX_ARG) #define BOOST_PP_FILENAME_1 "KSystemState.hpp" // this file #include BOOST_PP_ITERATE()
#undef BOOST_PP_FILENAME_1 #undef BOOST_PP_ITERATION_LIMITS
#undef _POST_PUSH #undef _POST_ARG
#endif // #ifndef _KSYSTEMSTATE_INL
1) 반복을 호출하는 부분
각각의 n 에 대해 자기자신KSystemState.hpp 를include 한다 .
31
#define n BOOST_PP_ITERATION()
template<BOOST_PP_ENUM_PARAMS(n, typename T)> void KSystemStateEvent::PostStateEvent( const char* pszInEvent , BOOST_PP_ENUM( n, _POST_ARG, ~) ) { BOOST_PP_REPEAT( n, _POST_PUSH, ~ ) }
#undef n
2) 되풀이 되는 패턴을 제공하는부분
각각의 n 에 대해 (n 이 1, 2 일 때 ) 확장된다 .
32
…
#define POST_STATE_MAX_ARG 4
class KSystemStateEvent{…};//class KSystemStateEvent
#include "KSystemState.hpp"
KSystemStateEvent g_systemState;
void main(){ g_systemState.PostStateEvent( "Input", 0 ); g_systemState.PostStateEvent( "Output", 1, "dummy", 1.2f, 0xff );//Input:0//Output:1//Output:dummy//Output:1.2//Output:255// 계속하려면아무키나누르십시오 . . .}//main()
이제 자유롭게 아규먼트의 개수만 정의하면 됩니다 ^^;
참고문헌
• David Abrahams, “C++ Template Metaprogramming”, 정보문화사 , p.323
• http://agile.egloos.com/5026291• http://www.boost.org/doc/libs/
1_38_0/libs/preprocessor/doc/index.html
33