Template Specialization

  • 특정 타입에 대한 템플릿을 별도로 제공하는 기법.
  • 예를 들어, vector<bool>처럼 bool 타입에 대해서만 다르게 동작하게 하고 싶을 때 사용. (bool만큼은 bit로 관리하는 게 효율적이기때문에)

종류

  1. primary template
      template<typename T> class Vector
      
  2. specialization
      template<typename T> Vecotr<bool>
      
  3. partial specialization
      template<typename T> class Vecotr<T*>
      

유의 1. 포인터 타입 제거

  #include <iostream>
#include <typeinfo>

// 기본 템플릿
template<typename T> struct remove_pointer {
    static void print() {
        std::cout << typeid(T).name() << std::endl;
    }
};

// 특수화 버전 (포인터 타입)
template<typename T> struct remove_pointer<T*> {
    static void print() {
        std::cout << typeid(T).name() << std::endl;
    }
};

int main() {
    remove_pointer<int>::print();     // int
    remove_pointer<int*>::print();    // int
}
  
  • remove_pointer<int*>T = int로 매칭됨.
  • 포인터 타입을 제거하는 특수화 버전이 호출됨.

유의 2. Partial Specialization 시 Default Parameter 표기 금지

  #include <iostream>

// Primary Template
template<typename T1, typename T2 = T1>
struct Object {
    static void print() {
        std::cout << typeid(T1).name() << ", " << typeid(T2).name() << std::endl;
    }
};

// Partial Specialization (default parameter 표기 X)
template<typename T1, typename T2>
struct Object<T1*, T2> {
    static void print() {
        std::cout << typeid(T1).name() << ", " << typeid(T2).name() << std::endl;
    }
};

int main() {
    Object<int*>::print();  // int, int*
}
  
  • Partial Specialization에서는 default parameter (= T1)를 다시 표기하지 않음.
  • Primary Template의 default를 그대로 사용.

사용 사례. Primary 버전만 선언하고 Specialization만 제공하기

  // Primary 선언만 (정의 없음)
template<typename T, int N>
struct Object;

// Specialization만 정의

// N = 1
template<typename T>
struct Object<T, 1> {
    static void info() { std::cout << "Specialization N=1" << std::endl; }
};

// N = 2
template<typename T>
struct Object<T, 2> {
    static void info() { std::cout << "Specialization N=2" << std::endl; }
};

int main() {
    Object<int, 1>::info();  // Specialization N=1
    Object<int, 2>::info();  // Specialization N=2
    // Object<int, 3> obj;   // Error! primary 정의 없음
}
  
  • Primary는 선언만 하고, 특정 조건(N=1, N=2)만 제공할 수 있음.
  • 다른 경우(N=3)는 에러 발생.

std::conditional 활용

  • 조건에 따라 타입을 선택하는 메타 프로그래밍 기법.
  • std::conditional<조건, Type1, Type2>::type
  • 조건이 true면 Type1, false면 Type2 선택.

std::conditional 직접 구현

  #include <iostream>

// Primary Template
template<bool Cond, typename T1, typename T2>
struct conditional {
    using type = T1;
};

// Specialization (Cond = false)
template<typename T1, typename T2>
struct conditional<false, T1, T2> {
    using type = T2;
};

int main() {
    using T = conditional<true, int, double>::type;
    std::cout << typeid(T).name() << std::endl;  // int
}
  
  • 조건에 따라 타입을 선택하는 기본적인 템플릿 메타 프로그래밍 예시.