Notice
Recent Posts
Recent Comments
Link
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
Archives
Today
Total
관리 메뉴

nomad-programmer

[Programming/C++] 클래스 템플릿의 특수화(Class Template Specialization) 본문

Programming/C++

[Programming/C++] 클래스 템플릿의 특수화(Class Template Specialization)

scii 2021. 2. 7. 16:41

클래스 템플릿의 특수화 방법 및 개념은 함수 템플릿과 매우 유사하다.

클래스 템플릿 특수화

함수 템플릿을 특수화하는 이유는 특정 자료형에 대해서 구분이 되는 다른 행동을 보이기 위해서다. 마찬가지로 클래스 템플릿을 특수화하는 이유는 특정 자료형을 기반으로 생생도니 객체에 대해, 구분이 되는 다른 행동양식을 적용하기 위해서이다.

즉, 클래스 템플릿을 특수화하면, 템플릿을 구성하는 멤버함수의 일부 또는 전부를 다르게 행동하도록 정의할 수 있다. 클래스 템플릿을 특수화하는 방법은 다음과 같다.

먼저 다음과 같이 정의된 클래스 템플릿이 존재할 때,

template <typename T>
class SoSimple {
  public:
    T SimpleFunc(T num) { ... }
}

이를 기반으로 자료형 int에 대해 특수화 한 템플릿 클래스는 다음과 같이 정의한다.

template <>
class SoSimple<int> {
  public:
    int SimpleFunc(int num) { ... }
};

이렇게 int형에 대해서 특수화가 되고 나면, 다음의 형태로 객체생성 시,

SoSimple<int> obj;

특수화된 템플릿 클래스 SoSimple<int>를 대상으로 객체가 생성된다. 

#include <iostream>

#pragma warning(disable: 4996)

using std::cout;
using std::cin;
using std::endl;


template <typename T>
class Point {
private:
    T xpos, ypos;

public:
    Point(T x = 0, T y = 0) : xpos(x), ypos(y) {}

    void ShowPosition() const {
        cout << '[' << xpos << ", " << ypos << ']' << endl;
    }
};

template <typename T>
class SimpleDataWrapper {
private:
    T mdata;

public:
    SimpleDataWrapper(T data) : mdata(data) {}

    void ShowDataInfo(void) const {
        cout << "Data: " << mdata << endl;
    }
};

template <>
class SimpleDataWrapper<char*> {
private:
    char* mdata;
    
public:
    SimpleDataWrapper(char* data) {
        mdata = new char[strlen(data) + 1];
        strcpy(mdata, data);
    }

    void ShowDataInfo(void) const {
        cout << "String: " << mdata << endl;
        cout << "Length: " << strlen(mdata) << endl;
    }

    ~SimpleDataWrapper() {
        delete[] mdata;
    }
};

template <>
class SimpleDataWrapper<Point<int>> {
private:
    Point<int> mdata;

public:
    SimpleDataWrapper(int x, int y) : mdata(x, y) {}

    void ShowDataInfo(void) const {
        mdata.ShowPosition();
    }
};


 int main(const int argc, const char* const argv[]) { 
     SimpleDataWrapper<int> iwrap(170);
     iwrap.ShowDataInfo();
     SimpleDataWrapper<char*> swrap((char*)"Class Template Specialization");
     swrap.ShowDataInfo();
     SimpleDataWrapper<Point<int>> poswrap(3, 7);
     poswrap.ShowDataInfo();

     return 0;
}
 
/* 결과

Data: 170
String: Class Template Specialization
Length: 29
[3, 7]

*/

위의 예제에서 char* 형에 대해서 특수화를 진행하였다. 이는 문자열을 저장하기 위한 것으로써, 이를 목적으로 동적할당 기반의 생성자와 소멸자를 별도로 정의하였다. 또한 템플릿 클래스인 Point<int> 형에 대해서도 특수화를 진행하였다.


클래스 템플릿의 부분 특수화

다음과 같이 정의된 클래스가 있다고 가정해보자.

template <typename T1, typename T2>
class MySimple { ... }

여기서 T1과 T2를 각각 char와 int로 하여 특수화를 진행하면 다음의 형태가 된다.

template <>
class MySimple<char, int> { ... }

그렇다면 다음의 정의는 어떤 의미일까?

template <typename T>
class MySimple<T, int> { ... }

MySimple 클래스 템플릿에 대한 특수화 결과이다. 단, T1과 T2 모두에 대해서 특수화를 진행한 것이 아닌, T2 하나에 대해서만 부분적으로 특수화를 진행한 것이다.

그래서 이를 가리켜 '클래스 템플릿의 부분 특수화(class template partial specialization)' 라 한다.

#include <iostream>

#pragma warning(disable: 4996)

using std::cout;
using std::cin;
using std::endl;


template <typename T1, typename T2>
class MySimple {
public:
    void Show() const {
        cout << "size of T1: " << sizeof(T1) << endl;
        cout << "size of T2: " << sizeof(T2) << endl;
        cout << "<typename T1, typename T2>" << endl;
    }
};

template <>
class MySimple<int, double> {
public:
    void Show() const {
        cout << "size of T1: " << sizeof(int) << endl;
        cout << "size of T2: " << sizeof(double) << endl;
        cout << "<int, double>" << endl;
    }
};

template <typename T1>
class MySimple<T1, double> {
public:
    void Show() const {
        cout << "size of T1: " << sizeof(T1) << endl;
        cout << "size of double: " << sizeof(double) << endl;
        cout << "<T1, double>" << endl;
    }
};


 int main(const int argc, const char* const argv[]) { 
     MySimple<char, double> obj1;
     obj1.Show();
     MySimple<int, long> obj2;
     obj2.Show();
     MySimple<int, double> obj3;
     obj3.Show();

     return 0;
}
 
/* 결과

size of T1: 1
size of double: 8
<T1, double>
size of T1: 4
size of T2: 4
<typename T1, typename T2>
size of T1: 4
size of T2: 8
<int, double>

*/

위의 실행 결과를 통해 알 수 있는 것은 다음과 같다.

부분 특수화와 전체 특수화의 두 가지 모두에 해당하는 객체생성 문장에서는 전체 특수화된 클래스를 대상으로 객체가 생성됨을 확인할 수 있다.

따라서 전체 특수화가 부분 특수화보다 우선시 된다고 생각하면 된다.

Comments