Updated:

3 minute read

개요

  • template <typename T1, typename T2> class Test
  • 특수화
    • template <typename T1, typename T2> class Test<T1 *, T2 *> {
  • 부분 특수화
    • template <typename T2> class Test<int, T2> {
  • 함수 템플릿
    • template <typename T1, typename T2> void func(T1 t1, T2 t2)
  • 함수 템플릿 특수화
    • 특수화를 지원하지 않고 오버로딩으로 해결
    • template <> void func(char t1, string t2) {
  • 논타입 템플릿 인자
    • template <typename T1, int add>
  • 디폴트 템플릿 인자
    • template <typename T = int>
    • template <typename T1, int add = 5>
  • 가변인자 템플릿
    • template <typename Type, typename... Types>
  • fold expression
    • C++17
    • ‘…’ 위치에 따라 ‘()’의 위치를 결정
    • template <typename... Types> void func7(Types... ts) { cout << (... + ts) << endl; }
    • (E op …)
      • (E1 op (… op (EN-1 op EN)))
    • (… op E)
      • (((E1 op E2) op …) op EN)
    • (E op … op I)
      • (E1 op (… op (EN?1 op (EN op I))))
    • (I op … op E)
      • ((((I op E1) op E2) op …) op EN)
  • 템플릿 메타 프로그래밍(Template Meta Programming)
    • 템플릿을 사용하여 컴파일 타임에 생성되는 코드를 이용하는 프로그래밍 기법
    • 장점
      • 컴파일 타임에 연산을 처리하므로 실행 속도 증가
    • 단점
      • 구현이 복잡
      • 코드 가독성 저하
      • 컴파일 타임에 연산을 처리하므로 디버깅 불가


예제

  • 코드
     #include <functional>
     #include <iostream>
     #include <typeinfo>
        
     using namespace std;
        
     template <typename T1, typename T2> class Test {
         public:
             Test() { cout << "main" << endl; }
     };
     template <typename T1, typename T2> class Test<T1*, T2*> {
         public:
             Test() { cout << "specialization" << endl; }
     };
     template <typename T2> class Test<int, T2> {
         public:
             Test() { cout << "partial specialization 1" << endl; }
     };
     template <> class Test<int, double> {
         public:
             Test() { cout << "partial specialization 2" << endl; }
     };
        
     template <typename T1, typename T2> void func1(T1 t1, T2 t2) {
         cout << "main : " << typeid(t1).name() << ", " << typeid(t2).name() << endl;
     }
     template <typename T1, typename T2> void func1(T1* t1, T2* t2) {
         cout << "specialization" << endl;
     }
     template <typename T2> void func1(int t1, T2 t2) {
         cout << "partial specialization 1" << endl;
     }
     template <> void func1(int t1, double t2) { cout << "partial specialization 2" << endl; }
     template <int i> void func1() { cout << i << endl; }
        
     template <typename T = int> void func2(T t) { cout << typeid(t).name() << endl; }
        
     template <typename T, int add> void func3(T t, int i) { t(i + add); }
        
     template <typename T, int add = 5> void func4(T t, int i) { t(i + add); }
        
     template <typename Type> void func5(Type t) { cout << t << endl; }
     template <typename Type, typename... Types> void func5(Type t, Types... ts) {
         cout << t << ", ";
         func5(ts...);
     }
        
     template <typename... Types> void func6(Types... ts) { cout << sizeof...(ts) << endl; }
        
     template <typename Type, typename... Types> void func7(Type t, Types... ts) {
         cout << (... + ts) << endl;
         cout << (ts - ...) << endl;
         cout << (t + ... + ts) << endl;
        
         auto f = [](int i) { cout << i << endl; };
         (f(ts), ...);
     }
        
     int factorial_recursion(int n) {
         if (n == 0) {
             return 1;
         }
        
         return n * factorial_recursion(n - 1);
     }
        
     template <int N> struct Factorial_TMP {
             enum { value = N * Factorial_TMP<N - 1>::value };
     };
     template <> struct Factorial_TMP<0> {
             enum { value = 1 };
     };
        
     int main() {
         Test<char, int>();
         Test<int*, char*>();
         Test<int, char>();
         Test<int, double>();
        
         cout << "------" << endl;
        
         func1('c', 1);
         func1(new int(1), new char('c'));
         func1(1, 'c');
         func1(1, 1.1);
         func1<5>();
        
         cout << "------" << endl;
        
         func2(1);
         func2<double>(1);
        
         cout << "------" << endl;
        
         function<void(int)> f = [](int i) { cout << i << endl; };
         func3<function<void(int)>, 1>(f, 1);
         func3<function<void(int)>, 2>(f, 1);
         func4(f, 1);
        
         cout << "------" << endl;
        
         func5(1, 'a');
         func5("abc", 1.1, "!");
        
         cout << "------" << endl;
        
         func6(1);
         func6(1, 'a');
        
         cout << "------" << endl;
        
         func7(1, 2, 3);
        
         cout << "------" << endl;
        
         cout << factorial_recursion(10) << endl;
         cout << Factorial_TMP<10>::value << endl;
        
         return 0;
     }
    
  • 실행 결과
    main
    specialization
    partial specialization 1
    partial specialization 2
    ------
    main : c, i
    specialization
    partial specialization 1
    partial specialization 2
    5
    ------
    i
    d
    ------
    2
    3
    6
    ------
    1, a
    abc, 1.1, !
    ------
    1
    2
    ------
    5
    -1
    6
    2
    3
    ------
    3628800
    3628800