본문 바로가기
c++/template프로그래밍.

templateSpecialization, meta template.. (특수화, 메타 템플릿..)

by kcj3054 2022. 5. 16.

기본1 함수 특수화..

기본 1 함수 특수화 소스

#include <iostream>

using namespace std;

//primary template
template<typename T>
class Stack
{
public:
    void push(T a)
};

//partial specialization (부분 특수화..)
template<typename T>
class Stack<T*>
{
public:
    void push(T a)
};

//specialization 특수화.. 완벽하게 타입이 char*로 결정되어서 template<?>에서 ?가 필요없다..
template<> 
class Stack<char*>
{
public:
    void push(char* a)
    {}
};
int main()
{
    Stack<int> s1; s1.push

    return 0;
}
  • 위에서 일반적인 템플릿은 primary template이라고한다. 그리고 특수화는 부분 특수화랑, 특수화 두개가 있는데 특수화는 명확하게 타입이 정해진 상태이고, 부분 특수화는 명확하게 정해지진않았다. 그래서 명확하게 정해진 특수화는 앞의 template 에서 T를 제거해도된다.

재귀적 모양의 특수화..

// 재귀적 모양의 특수화..  
template<typename T, typename U, typename V>
struct Test<T, Test<U, V> > 
{
    static void foo()
    {
        cout << "T, Test<U, V> " << endl;
    }
};
  • 만약 Test<double, Test<char, short>>::foo();를 호출 하고 싶으면.. 템플릿인자가 3개가 있어야한다. 그럼 특수화를 통해서 3개를 하는데 여기서 보면 하나는 템플릿인자 두번재는 템플릿안의 템플릿이있다.. 재귀적 모양이다. 이렇게하면 일단 특수화버전의 템플릿인자는 3개를 받고, 특수화부분을 잘 보자.
  • 특수화부분에 struct Test<T, 재귀부분.!> 재귀부분에 한번 더 Test가 들어가게된다 Test<T, Test<U, V>
  • primary template의 템플릿 인자가 2개라면, 사용자는 반디스 템플릿 인자를 2개 전달해야한다. 부분 특수화 버전을 만들 때 템플릿 인자의 개수는 primary template의 인자의 개수와 다를 수 있다. 단 부분 특수화의 선언에는 반드시 템플릿 인자가 2개야한다.
template<typename T> //템플릿인자 
struct Test<int, T>  // 부분 특수화 선언
{
    static void foo()
    {
        cout << "int, T" << endl;
    }
};

부분 특수화 주의 점.

  • default 값은 primary template에만 적용하되, 밑의 부분 특수화에는 default parameter를 적용하지 않는다..
template<typename T, int N  = 10> 
struct Stack
{
    T buff[N];
};

//부분 특수화에는 defaul parameter를 적용하지 않는다..  
template<typename T, int N>
struct Stack<T*, N>
{
    T buff[N];
};

int main()
{
    Stack<int, 10> s1;

    Stack<int*> s3;  // N = 10;
    return 0;
}

특수화 복잡한 버전..

//default 값 적용 부분..!! 
template<typename T1, typename T2 = T1>
struct Object
{
    static void print()
    {
        cout << typeid(T1).name() << ", " << typeid(T2).name() << endl;
    }
};

template<typename T1, typename    T2>
struct Object<T1*, T2>
{
    static void print()
    {
        cout << typeid(T1).name() << " " << typeid(T2).name() << " " << endl;
    }
};

int main()
{
    Object<int*>::print(); 
                        //int, int*
}
  • 위의 소스에서. Object<int>::print()가 int, int 로 되는 과정을 보자.

  • 결론은 매칭은 두번재 부분특수화에 매칭된다

  • 그렇지만 default값은 primary template쪽에서 T1 = T2가 되었기에 특수화의 T2는 int*로 된다.

템플릿 메타 프로그래밍

  • 템플릿은 일반적으로 컴파일 타임에 결정된다. 이러한 것을 활용한 것이 템플릿 메타프로그래밍이다..
  • 메타 템플릿은 c++11이 발표되기전에 사용... 현재는 modernc++에서는 constexpr 함수 사용..
constexpr size_t factorial(size_t n)
{
    return n == 1 ? 1 : n * factorial(n - 1);
}

int main()
{
    constexpr size_t ret = factorial(5);
    cout << ret << endl;
}
  • 원래 메타프로그래밍에서는 재귀를 사용하면서 재귀 종료를 위해서 특수화를 사용했는데 constexpr을 사용하면서, 간단해졌다..