24
17. 메메 메메메메메 ''Metaprogramming is the writing of computer programs that write or manipulate other programs (or themselves) as their data, or that do part of the work at compile time that would otherwise be done at runtime. In many cases, this allows programmers to get more done in the same amount of time as they would take to write all the code manually, or it gives programs greater flexibility to efficiently handle new situations without recompilation."

17. 메타 프로그래밍

  • Upload
    edana

  • View
    42

  • Download
    0

Embed Size (px)

DESCRIPTION

17. 메타 프로그래밍. - PowerPoint PPT Presentation

Citation preview

Page 1: 17.  메타 프로그래밍

17. 메타 프로그래밍

''Metaprogramming is the writing of computer programs that write or manipulate other programs (or themselves) as their data, or that do part of the work at compile time that would otherwise be done at runtime. In many cases, this al-lows programmers to get more done in the same amount of time as they would take to write all the code manually, or it gives programs greater flexibility to efficiently handle new sit-uations without recompilation."

Page 2: 17.  메타 프로그래밍

메타 프로그래밍 이란 ?: 프로그램을 프로그래밍 하는 것 .

왜 쓰나 ?: 적은 노력으로 더 많은 기능을 구현하기 위해 . 성능상의 이득도 얻는다 .

그리고 왠지 자신의 코드가 예술로 승화되는 것 같은 착각 .

Page 3: 17.  메타 프로그래밍

첫 번째 예제 코드 : 3^N

template < int N >class Pow3{public:

enum { result = 3 * Pow3<N-1>::result };};template <>class Pow3<0>{public:

enum { result = 1 };};

재귀를 끝내기 위한전체 특수화

Page 4: 17.  메타 프로그래밍

Pow3<7>::result

3 * Pow3<6>::result

3 * Pow3<5>::result

3 * Pow3<4>::result

3 * Pow3<3>::result

3 * Pow3<2>::result

3 * Pow3<1>::result

3 * Pow3<0>::result

1

3*3*3*3*3*3*3*1

Page 5: 17.  메타 프로그래밍

enum ? const ?

struct TrueConstant{

enum { Three = 3 };static int const Four = 4;

};

Three, Four 둘다 상수다 .C++ 표준화를 거치며 정적 상수 초기화 개념이 도입되었다 .

Page 6: 17.  메타 프로그래밍

template < int N >class Pow3{public:

enum { result = 3 * Pow3<N-1>::result };};

template < int N >class Pow3{Public:

static int const result = 3 * Pow3<N-1>::result;};

lvalue 가 아님 , 주소를 갖지 않으며 참조로 전달되어도 정적 메모리를 잡아먹지 않음 .

lvalue 실질적인 메모리 할당이 이루어져야 하며 이것은 런타임에 발생함 .

Page 7: 17.  메타 프로그래밍

두번째 예제 : 제곱근

template < int N, int LO = 1, int HI = N >class Sqrt{public:

enum { mid = (LO + HI + 1) / 2 };enum { result = (N < mid*mid) ? Sqrt<N, LO, mid – 1>::result

: Sqrt<N, mid, HI>::result };};

template < int N, int M >class Sqrt<N, M, M>{public:

enum { result = M };};

Page 8: 17.  메타 프로그래밍

N < mid * mid

yes no

LO = 1 mid HI

LO mid - 1 mid HI

HI LO

Page 9: 17.  메타 프로그래밍

Sqrt<16>::result mid = (1 + 16 + 1) / 2 = 9

16 < 9*9

Sqrt<16, 1, 8>::result Sqrt<16, 9, 16>::result

mid = (1 + 8 + 1) / 2 = 5 mid = (9 + 16 + 1) / 2 = 13

Sqrt<16, 1, 4>::result Sqrt<16, 5, 8>::result

16 < 5*5

Sqrt<16, 9, 12>::result Sqrt<16, 13, 16>::result

16 < 13*13

…….…

Page 10: 17.  메타 프로그래밍

양쪽의 케이스 모두를 인스턴스화 .‘ :: ’ 연산자 사용 접근으로 인해 클래스형 내의 모든 멤버도 인스턴스화 .

삼항 연산자 대신 특수화를 이용 하자 .

template < bool C, typename T1, typename T2 >class IfThenElse;

template < typename T1, typename T2 >class IfThenElse<true, T1, T2>{public:

typedef T1 Result;};

template < typename T1, typename T2 >class IfThenElse<false, T1, T2>{public:

typedef T2 Result;};

Page 11: 17.  메타 프로그래밍

template < int N, int LO = 1, int HI = N >class Sqrt{public:

enum { mid = (LO + HI + 1) / 2 };typedef typename IfThenElse<(N < mid*mid), Sqrt<N, LO, mid-1>,

Sqrt<N, mid, HI> >::Result SubT;enum { result = SubT::result };

};

template < int N, int M >class Sqrt<N, M, M>{public:

enum { result = M };};

N < mid*mid 에 대한 값 (true, false) 의 방향에 대해서만 인스턴스화가 진행된다 .

Page 12: 17.  메타 프로그래밍

유도 변수

for ( int i = 1 ; i*i < N ; ++i ){

// do something.}

전형적인 C/C++ 에서의 제곱근 추적 루프

template < int N, int I = 1 >class Sqrt{public:

enum { result = (I * I < N) ? Sqrt<N, I + 1>::result : I };};

template < int N >class Sqrt<N, N>{public:

enum { result = N };};

I 를 유도변수라고 한다 .Induction variable

Page 13: 17.  메타 프로그래밍

Sqrt<4>::result

(1 * 1 < 4) ? Sqrt<4, 2>::result : 1

(2 * 2 < 4) ? Sqrt<4, 3>::result : 2

(3 * 3 < 4) ? Sqrt<4, 4>::result : 3

4

(1*1 < 4) ? ( (2*2 < 4) ? ( (3*3 < 4) ? 3 ) : 2 ) : 1

답은 2 번의 단계만에 도달하지만 인스턴스화는 최종적으로 부분 특수화에 도달하기 전까지 계속된다 .

Page 14: 17.  메타 프로그래밍

IfThenElse 템플릿 도입

template < int N >struct Value{public:

enum { result = N };};

template < int N, int I = 1 >class Sqrt{public:

typedef typename IfThenElse \<(I*I < N), Sqrt<N, I+1>, Value<I> >::ResultT SubT;

enum { result = SubT::result };};

Page 15: 17.  메타 프로그래밍

Sqrt<16>::result

IfThenElse<1*1 < 16, Sqrt<16, 2>, Value<1> >

IfThenElse<2*2 < 16, Sqrt<16, 3>, Value<2> >

IfThenElse<3*3 < 16, Sqrt<16, 4>, Value<3> >

IfThenElse<4*4 < 16, Sqrt<16, 5>, Value<4> >

Sqrt<16>::result = 4

Page 16: 17.  메타 프로그래밍

계산 완벽성

- 인스턴스화 횟수에 제한이 없다면 계산 가능한 모든 것을 메타프로그래밍을 통해 처리할 수 있을 것이다 .

- 하지만 , 현실적으로 컴파일러의 자원은 한정되어 있고 인스턴스의 재귀 횟수 또한 제한된다 .

- 또한 , 템플릿의 인스턴스화는 상당한 컴파일러 자원을 잡아먹는다 .

- 템플릿은 만능이 아니다 .

Page 17: 17.  메타 프로그래밍

재귀적 인스턴스화 , 재귀적 템플릿 인자

template < typename T, typename U >struct Doublify {};

template < int N >struct Trouble{

typedef Doublify<typename Trouble<N-1>::LongType,typename Trouble<N-1>::LongType> LogType;

};

template <>struct Trouble<0>{

typedef double LongType;};

Page 18: 17.  메타 프로그래밍

Trouble<10>::LongType ouch;

Doublify<Trouble<9>::LongType, Trouble<9>::LongType>

Doublify<Trouble<8>::LongType, Trouble<8>::LongType>

Doublify<Trouble<7>::LongType, Trouble<7>::LongType>

………………………..

Doublify<Trouble<0>::LongType, Trouble<0>::LongType>

dou-ble

Trouble<N>::LongType 의 복잡도는 N 의 지수승으로 증가한다 .재귀적 인스턴스화에 템플릿 인자는 재귀적인 형태를 피하는게 좋다 .

재귀적 템플릿 인자를 포함하는 재귀적 인스턴스화는 포함하지 않는 경우의 재귀적 인스턴스화 보다 컴파일러에 가해지는 부하가 더 심하다 .

Page 19: 17.  메타 프로그래밍

루프를 풀기 위한 메타프로그래밍

template < typename T >inline T dot_product (int dim, T* a, T* b){

T result = T();for(int i = 0; i < dim; ++i){

result += a[i] * b[i];}return result;

}

내적을 계산하는 템플릿 코드

int a[3] = { 1, 2, 3 };int b[3] = { 5, 6, 7 };int dot = dot_product(3, a, b);

Page 20: 17.  메타 프로그래밍

int a[3] = { 1, 2, 3 };int b[3] = { 5, 6, 7 };int dot = dot_product(3, a, b);

for(int i = 0 ; i < 3 ; ++i){

result += a[i] * b[i];}

루프 보다는a[0] * b[0] + a[1] * b[1] + a[2] * b[2]

같은 직접적인 계산이 더 빠르다 .

- 지역 스택의 생성 / 소거- int i- 대입연산 , 임시 객체의 생성

….

Page 21: 17.  메타 프로그래밍

template < int DIM, typename T >class DotProduct{public:

static T result (T* a, T* b){

return (*a) * (*b) + DotProduct<DIM – 1, T>::result (a+1, b+1);}

};

template < typename T >class DotProduct<1, T>{public:

static T result (T* a, T* b){

return (*a) * (*b);}

};

template < int DIM, typename T >inline T dot_product (T* a, T* b){

return DotProduct<DIM,T>::result(a,b);}

Page 22: 17.  메타 프로그래밍

int a[3] = { 1, 2, 3 };int b[3] = { 3, 5, 7 };int dot = dot_product<3>(a, b);

static int result (int* a, int* b){

return (*a) * (*b) + DotProduct<3 – 1, T>::result (a+1, b+1);}

return (*a) * (*b) + DotProduct<2 – 1, T>::result (a+1, b+1);

a[0]

a[1]

b[0]

b[1]

return (*a) * (*b)a[2] b[2]

return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]

• 실질적으로 루프를 줄이는 것만으로는 성능 향상을 기대하기 힘들다 .Blitz++, MTL, POOMA 같은 라이브러리들은 이런 식의 메타프로그래밍 뿐 아니라 다양한 요소들을 고려하여 만들어진다 .

Page 23: 17.  메타 프로그래밍

template <int p, int i>class is_prime{public:enum { prim = (p == 2) || (p%i) && is_prime<(i>2 ? p : 0), i-1>::prim };};

template<>class is_prime<0,0>{public:enum { prim = 1 };};

template<>class is_prime<0,1>{public:enum { prim = 1 };};

template < int i >class D{public:D(void*);};

template < int i >class Prime_print{public:Prime_print<i-1> a;enum { prim = is_prime<i, i-1>::prim };

void f(){D<i> d = prim ? 1 : 0;a.f();}};

template<>class Prime_print<1>{public:enum { prim = 0 };

void f(){D<1> d = prim ? 1 : 0;}};

#define LAST 18

int main(){Prime_print<LAST> a;a.f();}

어윈 운러의 소수 계산 템플릿

Page 24: 17.  메타 프로그래밍

감사합니다