이전 포스팅에서 간단히 템플릿에 대해서 설명하였습니다.
우리가 template과 함께 typename 이라는 키워드를 사용하였습니다. 이 typename이라는 키워드는 템플릿 매개변수를 선언할 때 사용합니다. template <typename T> 처럼 사용하는 사람이 있고 template <class T> 로 사용하는 사람이 있는데 똑같이 동작합니다. typename이라는 키워드 자체를 타입이라고 명시를 시켜줄 때 사용할 수도 있습니다.
예를 들어 아래와 같이 코드를 작성했을 때 일반적인 상황에서는 전달받은 컨테이너가 가지고 있는 const_iterator 타입을 포인터 변수로 사용하는 코드가 됩니다. 하지만 만약에 전달받은 타입에 const_iterator라는 정적 변수가 있을 때에는 또 다른 의미를 가지게 됩니다. 그리고 x라는 전역 변수가 어딘가에 있다면 이 구문은 포인터 변수를 선언하는 코드가 아닌 단순 곱하기처럼 동작할 가능성을 지니게 됩니다.
template <typename T>
void print(const T& container)
{
T::const_iterator * x;
}
그렇기에 이러한 문제를 방지하기 위해 이것은 타입이다 라고 명시할 수 있게 typename 키워드를 앞에 붙여서 사용할 수 있습니다.
template <typename T>
void print(const T& container)
{
typename T::const_iterator * x;
}
템플릿으로 만들어진 클래스를 상속 받아 클래스를 하나 만들어 보겠습니다. Printer라는 클래스는 Test 변수를 하나 생성해서 printTest 함수를 호출합니다. 근데 이 Printer<T>를 상속받아 LogPrinter라는 클래스를 하나 더 만들고 이 안에서 print 함수를 호출하도록 하였습니다. 하지만 이대로 컴파일 시 에러가 나게 됩니다.
#include <iostream>
class Test {
public:
void printTest() { std::cout << "Test"; }
};
template <typename T>
class Printer {
public:
void print() {
T t;
t.printTest();
}
};
template <typename T>
class LogPrinter : public Printer<T> {
public:
void lprint() {
print();
}
};
int main()
{
LogPrinter<Test> lp;
lp.lprint();
}
이 print라는 함수를 컴파일 단계에서는 기본 클래스를 명확히 할 수 없기 때문에 컴파일 할 수가 없습니다. 기본 클래스가 전달받은 타입에 따라 print라는 함수가 없을 수도 있기 때문입니다. 이러한 에러를 해결하기 위해서는 아래 방법을 사용할 수 있습니다.
// this 사용
template <typename T>
class LogPrinter : public Printer<T> {
public:
void lprint() {
this->print();
}
};
// using을 통해 기본 클래스에 함수가 있음을 알려줌
template <typename T>
class LogPrinter : public Printer<T> {
public:
using Printer<T>::print;
void lprint() {
print();
}
};
// 명시적으로 기본 클래스의 함수 호출
template <typename T>
class LogPrinter : public Printer<T> {
public:
void lprint() {
Printer<T>::print();
}
};
이렇게 템플릿을 사용하면 코드의 수를 줄일 수 있을 뿐 아니라 유지보수 및 기타 부분에 대해서 장점을 지니게 됩니다. 하지만 이런 템플릿도 잘못된 방법으로 사용할 경우 쓸데없이 코드가 비대해질 수 있습니다. 아래 코드로 예를 들어보겠습니다.
아래와 같이 타입과 크기를 전달받는 클래스가 있을 때 아래와 같이 사용한다면 Array<int, 10>::invert와 Array<int, 20>::invert에 대한 인스턴스화 되게 됩니다.
template <typename T, int size>
class Array {
public:
void invert();
};
int main()
{
Array<int, 10> AInt10;
Array<int, 20> AInt20;
AInt10.invert();
AInt20.invert();
}
이러한 중복을 막기 위해서는 굳이 사이즈 값은 템플릿으로 받지 않고 멤버 함수의 매개변수로 받아 처리할 수도 있습니다.
template <typename T>
class Array {
public:
void invert(int nSize);
};
int main()
{
Array<int> AInt10;
Array<int> AInt20;
AInt10.invert(10);
AInt20.invert(20);
}
'Programming > C++' 카테고리의 다른 글
[C++] boost windows 비동기 처리하기 (2) | 2023.10.23 |
---|---|
[C++] Template(1) (2) | 2023.09.19 |
[C++] std::forward_list, std::list (0) | 2023.07.18 |
[C++] std::array, std::vector (0) | 2023.07.12 |
[C++] 람다 함수 (0) | 2023.04.07 |