C++/Templates 2021. 3. 22. 00:02

클래스 템플릿 특수화 (Class Templates Specialization)

  • 템플릿의 특정 자료형에 대해서 다르게 처리하고 싶을 때 사용한다.

  • 함수 템플릿 특수화에서는 template<>을 명시하지 않아도 작동이 됐는데, 클래스 템플릿 특수화에서는 명시하지 않으면 오류가 발생한다.

    error C2906: 'A<char>': explicit specialization requires 'template <>'

예제

  • 클래스 템플릿 특수화는 다른 클래스를 하나 따로 만들었다고 생각해야 한다.

    • 아래의 예제에서 a_char.test 함수는 존재하지 않는다. 상속과는 엄연히 다르다.
    #include "MyArray.h"
    
    using namespace std;
    
    template<typename T>
    class A
    {
    public:
      void doSomething()
      {
        cout << typeid(T).name() << endl;
      }
    
      void test() {}
    };
    
    template<>
    class A<char>
    {
    public:
      void doSomething()
      {
        cout << "Char type specialization\n";
      }
    };
    
    int            main()
    {
      A<int>        a_int;
      A<double>    a_double;
      A<char>        a_char;
    
      a_int.doSomething();
      a_double.doSomething();
      a_char.doSomething();
    }
    
    /* stdout
    int
    double
    Char type specialization
    */

비트마스크를 통한 메모리 절약 예제

  • 아래 예제에서 bool 자료형에 대해 클래스 템플릿 특수화를 하지 않는다면, Storage8 인스턴스는 8바이트의 크기를 차지하게 된다.

  • 대신 bool 자료형일 경우 비트마스크를 이용하여 메모리를 1/8 수준으로 절약할 수 있다.

    #include <iostream>
    
    using namespace std;
    
    template<typename T>
    class Storage8
    {
      T    array_[8];
    
    public:
      void        set(int index, const T& value)
      {
        array_[index] = value;
      }
    
      const T&    get(int index)
      {
        return array_[index];
      }
    };
    
    template<>
    class Storage8<bool>
    {
      unsigned char    data_;
    
    public:
      Storage8() : data_(0)
      {}
    
      void    set(int index, bool value)
      {
        unsigned char mask = 1 << index;
    
        if (value)
          data_ |= mask;
        else
          data_ &= ~mask;
      }
    
      bool    get(int index)
      {
        unsigned char mask = 1 << index;
        return ((data_ & mask) != 0);
      }
    };
    
    int            main()
    {
      Storage8<int> intStorage;
    
      for (int count = 0; count < 8; ++count)
        intStorage.set(count, count);
      for (int count = 0; count < 8; ++count)
        cout << intStorage.get(count) << '\n';
      cout << "Sizeof Storage8<int> : " << sizeof(Storage8<int>) << endl;
    
      Storage8<bool> boolStorage;
    
      for (int count = 0; count < 8; ++count)
        boolStorage.set(count, count & 3);
      for (int count = 0; count < 8; ++count)
        cout << std::boolalpha << boolStorage.get(count) << '\n';
      cout << "Sizeof Storage8<bool> : " << sizeof(Storage8<bool>) << endl;
    }
    
    /* stdout
    0
    1
    2
    3
    4
    5
    6
    7
    Sizeof Storage8<int> : 32
    false
    true
    true
    true
    false
    true
    true
    true
    Sizeof Storage8<bool> : 1
    */