반응형

템플릿 특수화(Template specialization), 부분 특수화(Partial specialization) 개념

  • 템플릿의 특정 패턴에 대해서 별도의 처리가 하고 싶을 경우 부분 특수화 또는 특수화를 이용할 수 있음
  • 메인 템플릿의 인자가 2개라면, 사용자는 반드시 템플릿 인자를 2개 전달해야 한다.(기본값이 없다면)
  • 부분 특수화(Partial specialization) 템플릿에서는 인자의 수는 메인 템플릿 인자수와 다를 수 있다.
  • 특수화를 많이 할 경우 소스코드가 늘어날 수는 있지만 결국 목적코드로 생성되는 기계어 코드의 양은 같음
#include <iostream>
using namespace std;

// 메인 템플릿(Primary template)
// 기본적으로 모든 패턴은 메인 템플릿이 처리함
template<typename T> class stack
{
public:
    void push(T a) { cout << "T" << endl; }
};

// 부분 특수화(Partial specialization)
// 모든 포인터 타입에 대해서 별도로 처리하고 싶을 경우 부분 특수화를 적용할 수 있음
template<typename T> class stack<T*>
{
public:
    void push(T* a) { cout << "T*" << endl; }
};

// 특수화(Speicalization)
// char포인터에 대해서만 별도로 처리하고 싶을 경우 특수화를 적용할 수 있음
template<> class stack<char*>
{
public:
    void push(char* a) { cout << "char*" << endl; }
};


int main()
{
    stack<int> s1; s1.push(0); // 메인 템플릿 사용
    stack<int*> s2; s2.push(0); // 부분 특수화 템플릿 사용
    stack<char*> s3; s3.push(0); // 특수화 템플릿 사용
}

 

템플릿 특수화(specialization)/부분 특수화(Partial specialization) 예제

#include <iostream>
using namespace std;

// 1. <T, U> 메인 템플릿
template<typename T, typename U> class test
{
public:
    static void foo() { cout << "T, U" << endl; }
};

// 2. <T*, U> 부분 특수화
template<typename T, typename U> class test<T*, U>
{
public:
    static void foo() { cout << "T*, U" << endl; }
};

// 3. <T*, U*> 부분 특수화
template<typename T, typename U> class test<T*, U*>
{
public:
    static void foo() { cout << "T*, U*" << endl; }
};

// 4. <T, T> 부분 특수화
template<typename T> class test<T, T>
{
public:
    static void foo() { cout << "T, T" << endl; }
};

// 5. int, T
template<typename T> class test<int, T>
{
public:
    static void foo() { cout << "int, T" << endl; }
};

// 5. <int, T> 부분 특수화
template<> class test<int, int>
{
public:
    static void foo() { cout << "int, int" << endl; }
};

// 6. <int, short> 특수화
template<> class test<int, short>
{
public:
    static void foo() { cout << "int, short" << endl; }
};

// 7. T, test<U, V> 부분 특수화
template<typename T, typename U, typename V> 
class test<T, test<U, V>>
{
public:
    static void foo() { cout << "T, test<U, V>" << endl; }
};

int main()
{
    // 1. <T, U> 메인 템플릿
    test<int, double>::foo();

    // 2. <T*, U> 부분 특수화
    test<int*, double>::foo();

    // 3. <T*, U*> 부분 특수화
    test<int*, double*>::foo(); 

    // 4. <T, T> 부분 특수화
    test<int, int>::foo();

    // 5. <int, T> 부분 특수화
    // 인자가 <int, int>일 경우 4.<T, T> 5.<int, T> 패턴이 2개이상 일치하므로 5-1 특수화 추가 구현 필요
    test<int, char>::foo(); 

    // 6. <int, short> 특수화
    test<int, short>::foo(); 

    // 7. T, test<U, V> 부분 특수화
    test<double, test<char, short>>::foo();
}

 

템플릿 특수화(specialization)/부분 특수화(Partial specialization) 주의사항

  • 부분 특수화에서 T의 타입이 결정되는 방식을 주의해야 함
  • 부분 특수화에서 기본 파라미터는 표시하지 않음(메인 템플릿에 정의 값을 그대로 승계함)
  • 클래스의 특정 멤버 함수만 특수화 할 수 있으나 부분 특수화는 불가능
// 부분 특수화 시 T 타입의 주의
// 메인 템플릿에 포인터값이 넘어 왔을 경우 T는 포인터 타입임
template<typename T> class Test
{
public:
    static void foo() { cout << typeid(T).name() << endl; }
};

// 아래와 같이 포인터 타입으로 부분 특수화를 했을 경우 T는 포인터 타입이 아님
template<typename T> class Test<T*>
{
public:
    static void foo() { cout << typeid(T).name() << endl; }
};
// 메인 템플릿에 정의된 파라미터 기본 파라미터
template<typename T, int N = 10> class Test
{
public:
    static void foo() { cout << typeid(T).name() << endl; }
};

// 부분 특수화에서는 기본 파라미터를 표시하지 않음(메인 템플릿의 기본 파라미터 값 승계)
template<typename T, int N> class Test<T*, N>
{
public:
    static void foo() { cout << typeid(T).name() << endl; }
};
// 클래스 템플릿
template<typename T>
class Stack
{
public:
    T pop() {}
    void push(T a);
};

// 특정 멤버 함수의 특수화가 필요할 경우 구현부를 분리
template<typename T>
void Stack<T>::push(T a)
{
    cout << "T" << endl;
}

// 특정 멤버 함수의 특수화 구현(부분 특수화는 불가능함)
template<>
void Stack<char*>::push(char* a)
{
    cout << "char*" << endl;
}

int main()
{
    Stack<int> s1; s1.push(0);
    Stack<char*> s2; s2.push(0);
}

 

반응형

+ Recent posts