이 글은 개인의 학습을 목적으로 정리한 글입니다. 이점 참고하고 읽어주세요 ;)
이번 포스팅에서는 이전의 여러 포스팅에서 다룬 템플릿을 부분적으로 특수화하는 방법을 알아보겠습니다.
template <class T, int size>
class StaticArray
{
private:
T m_array[size];
public:
T* getArray() { return m_array; }
T& operator[](int index)
{
return m_array[index];
}
};
여기 StaticArray 클래스를 정의했습니다. 템플릿을 사용했고 첫 번째 매개변수인 typename은 T 클래스로, 두 번째 매개변수는 자료형이 아닌 int형 변수 size로 설정했습니다.
클래스의 멤버로는 생성자와 배열을 리턴하는 getArray 함수, 그리고 첨자([ ])연산자입니다.
template<typename T, int size>
void print(StaticArray<T, size>& array)
{
for (int count = 0; count < size; ++count)
std::cout << array[count] << ' ';
std::cout << endl;
}
추가적으로 StaticArray 인스턴스를 출력하는 print 함수를 만들었습니다. 템플릿 선언은 StaticArray와 동일하고, 매개변수로 StaticArray 클래스의 인스턴스를 레퍼런스(&)로 가져옵니다.
int main()
{
StaticArray<int, 4> int4;
int4[0] = 1;
int4[1] = 2;
int4[2] = 3;
int4[3] = 4;
print(int4);
return 0;
}
그리고 이를 main 함수에서 이런식으로 사용합니다. 클래스의 멤버로 첨자([ ]) 연산자를 정의했기 때문에 인스턴스에 바로 첨자를 사용할 수 있습니다.
print 함수에 따라 문제없이 int4의 멤버들이 차례로 출력되는 걸 볼 수 있습니다.
int main()
{
StaticArray<char, 14> char14;
strcpy_s(char14.getArray(), 14, "Hello, World");
print(char14);
return 0;
}
이번에는 char 자료형으로 StaticArray 클래스의 인스턴스를 만들었습니다.
char 자료형 멤버를 14개 저장하는 배열입니다.
strcpy_s를 통해 char14에 "Hello, World"라는 문자열을 입력하고 print 함수를 호출했습니다.
(알 수 없는 에러가 발생해서 문자열이 중간에 출력되다 멈춰버렸는데......;;;)
char 자료형 인스턴스 역시 출력이 됩니다. 하지만 문자열이니까 좀 더 읽기 편하게 char 자료형으로 StaticArray 클래스의 인스턴스에서 print 함수를 호출할 때에는 출력 양식을 바꿔주고 싶습니다.
이때 필요한 것이 템플릿의 부분적 특수화입니다.
template<typename T, int size> // 기존의 print 함수
void print(StaticArray<T, size>& array)
{
for (int count = 0; count < size; ++count)
std::cout << array[count] << ' ';
std::cout << endl;
}
template<int size> // 부분적 템플릿 특수화를 해준 print 함수
void print(StaticArray<char, size>& array)
{
for (int count = 0; count < size; ++count)
std::cout << array[count];
std::cout << endl;
}
두 print 함수 중 위에 있는 코드는 기존의 print 함수이고, 아래에 있는 print 함수가 부분적 템플릿 특수화를 해준 print 함수입니다.
이전에 작성한 템플릿 특수화 포스팅을 읽은 분들은 아시겠지만,
템플릿 특수화를 해줄 때 템플릿 매개변수에서 특수화를 해줄 멤버는 입력하지 않습니다.
예제의 print함수는 원래 템플릿 매개변수로 typename T와 int size를 가지고 있습니다. 우리는 배열의 자료형만 특수화하기 때문에 배열의 크기를 정하는 int size만 템플릿의 매개변수로 입력합니다.
그리고 기존의 print 함수에서 StaticArray<T, size>로 받았던 매개변수를 StaticArray<char, size>로 특수화 해줍니다.
마지막으로 print 함수가 출력할 때 띄어쓰기를 하지 않도록 함수의 바디를 변경해주면 부분적 템플릿 특수화가 마무리됩니다.
int main()
{
StaticArray<char, 14> char14;
strcpy_s(char14.getArray(), 14, "Hello, World");
print(char14);
return 0;
}
그리고 다시 main 함수를 실행시키면
char 자료형을 사용하는 StaticArray 클래스 인스턴스인 char14 배열의 멤버들이 띄어쓰기(' ') 없이 읽기 편하게 출력된 걸 볼 수 있습니다.
위의 코드들에서는 StaticArray 클래스 밖에 print 함수를 따로 정의했습니다. 이번에는 print 함수를 클래스의 멤버로 포함시키고, 그럴 때 부분적 템플릿 특수화를 하는 방법을 알아보겠습니다.
void print()
{
for (int count = 0; count < size; ++count)
std::cout << array[count] << ' ';
//std::cout << (*this)[count] << ' '; 동일하게 작동
std::cout << endl;
}
일단 클래스 밖에서 정의되었던 print 함수를 클래스의 멤버로 추가시킵니다. 위의 코드 블록과 같이 추하가면 됩니다.
클래스 밖에 있을 때와 변화된 점이라면,
어차피 클래스 속에서 클래스의 멤버들에 접근할 수 있기 떄문에 함수의 매개변수를 입력하지 않는 점입니다.
그리고 출력 부분에서 array[count]는 (*this)[count] 이렇게 this 포인터를 사용해도 똑같이 작동합니다.
StaticArray<char, 14> char14;
char14[0] = 'H';
strcpy_s(char14.getArray(), 14, "Hello, World");
char14.print();
그리고 main 함수에서는 print 함수에 매개변수를 주지 않고 char14 인스턴스에서 멤버로 출력하면 됩니다..
하지만 print 함수가 클래스의 멤버로 들어오는 경우 부분적 템플릿 특수화가 좀 번거로워진다고 합니다.
이를 간단히 해결하는 방법이 있는데, 바로 상속을 사용하는 것입니다.
template <class T, int size>
class StaticArray_BASE
{
.
.
우선 기존의 StaticArray를 부모 클래스로 바꾸기 위해 클래스의 이름을 StaticArray_BASE로 변경해줍니다.
template <class T, int size>
class StaticArray : public StaticArray_BASE<T, size>
{};
그리고 그 아래에 StaticArray_BASE 클래스를 상속받는 StaticArray 클래스를 다시 정의합니다.
이렇게 되면 StaticArray가 StaticArray_BASE를 통째로 상속받기 때문에 main 함수에 정의된 char14 인스턴스는 무리 없이 작동합니다. 다만 아직 char 자료형에 대해 템플릿 특수화를 하지 않았기 때문에 띄어쓰기가 포함된 출력이 나옵니다.
template <int size>
class StaticArray<char, size> : public StaticArray_BASE<char, size>
{
public:
void print()
{
for (int count = 0; count < size; ++count)
std::cout << (*this)[count];
std::cout << endl;
}
};
이제 char 자료형에 대해 print 함수를 특수화하기 위해 StaticArray 클래스를 다시 템플릿을 사용하여 생성하고 StaticArray_BASE를 상속받습니다. 템플릿 특수화 방법은 위에서 했던 그대로 템플릿 매개변수를 변경하면 됩니다.
그리고 클래스 내부에 원하는대로 기능을 정의하고 main 함수를 실행하면 아까와 같이 띄어쓰기가 사라진 출력을 볼 수 있습니다.
'Information Technology > C++' 카테고리의 다른 글
[C++] 예외처리와 스택 되감기 (0) | 2019.11.25 |
---|---|
[C++] 예외처리의 기본 (0) | 2019.11.21 |
[C++] 클래스 템플릿 특수화 (0) | 2019.11.20 |
[C++] 함수 템플릿 특수화 (0) | 2019.11.20 |
[C++] 자료형이 아닌 템플릿 매개변수 (0) | 2019.11.20 |