[C++] 템플릿(template)

우니·2022년 11월 1일
0

템플릿이란?

쉽게 설명하자면 뭔가를 찍어내기 위한 틀이다.
붕어빵 틀이 있다면 밀가루 반죽과 팥을 넣으면 붕어빵이 만들어진다.
근데 그 안에 밀가루가 아닌 찹쌀가루나 슈크림을 넣으면 모양은 같지만 맛이 다른 붕어빵을 만들 수 있다.

재료가 바뀌어도 템플릿은 사용할 수 있다는 뜻이다.
C++ 템플릿의 종류에는 두가지가 있다
1. 함수 템플릿
2. 클래스 템플릿

그렇다면, 템플릿이 틀이라는건 알았는데 안에 들어가는 재료는 무엇을 말하는걸까?
바로 데이터 타입이다.
즉, 템플릿을 이용하면 다양한 데이터 타입에 대해 동일한 기능을 하는 함수느 클래스를 찍어낼 수 있다.

템플릿의 필요성

예를들어 swap 함수를 만들어보자.

void swap(int &a, int &b)
{
	int temp;
    temp = a;
    a = b;
    b = temp;
}

두개의 int형 변수의 값을 서로 바꿔주는 기능을 한다.
이러한 기능을 하는 함수는 int형 뿐만이 아니라 다른 데이터 타입에도 필요할 수 있다.
double 형 변수의 값을 swap 해주는 함수가 필요하면

void swap(double &a, double &b)
{
	int temp;
    temp = a;
    a = b;
    b = temp;
}

이와 같은 함수를 만들어 호출하면된다.
근데 이 두 함수를 보면 데이터 타입만 다르지 그 외의 것들은 모두 똑같은걸 알 수 있다.
데이터 타입이 다르다는 이유로 이와 같이 똑같은 코드를 작성하고 반복하는 일은 매우 비생산적이다.
반복되는 코드를 처음에 작성할때는 복사+붙여넣기로 쉽게 작성할 수 있을진 모르나, 나중에 수정사항이 생긴다고 한다면....하나하나 확인하며 전부 수정을 해줘야한다.
지금은 코드가 두개지만 훨 많이 생긴다고 생각하면 정말 골치 아픈 일이다.

이런 경우 함수 템플릿을 이용하면 데이터 타입에 상관없는 함수를 만들 수 있다.

template<typename T>
void temp(T &a, T &b)
{
	int temp;
    temp = a;
    a = b;
    b = temp;
}

template과 typename은 템플릿을 정의할 때 쓴느 키워드이고 T는 식별자이다.
T는 함수이름이나 변수이름처럼 개발자가 마음대로 이름을 정할 수 있는것으로, 이 템플릿에서 일반화시킬 데이터 타입이다.

두 개 이상의 타입을 일반화하는 템플릿을 정의할 경우에는 다음과 같이 typename을 여러번 쓸 수 있다.

template<typename T1, typename T2>
void Function(T1 a, T2 b)
{
	'''
}

템플릿의 인스턴스화

템플릿 함수를 만들었다면 이제 동작과정을 알아보자.
템플릿 함수가 처리하는걸까? 싶을 수 있지만 그렇지 않다.
맨 처음에사도 말했듯이 템플릿은 함수를 찍어내는 틀의 역할만 할 뿐이지. 직접 동작을 하는 것은 아니다.

컴파일러가 함수 템플릿을 이용하여 int형을 인자로 받는 함수와 double형을 인자로 받는 함수 각각을 찍어낸다.
컴파일 결과는 int형 함수, double형 함수 각각 두개를 만들어준것과 똑같다.
그리하여 소스코드의 길이가 짧다고, 실행파일도 같이 작아질거라고 오해하는데 그렇지 않다.
실제 컴파일 결과 생성되는 바이너리 코드는 데이터 타입마다 함수를 각각 만든것과 똑같기 때문이다.
단, 실제 사용한 데이터 타입에 대해서만 이루어진다.

이와 같이 실제 동작 가능한 함수를 만들어 내는 것을 함수 템플릿을 인스턴스화 한다고 말한다.

클래스 템플릿

템플릿 함수처럼 클래스도 템플릿으로 찍어낼 수 있다.

template <typename T>
class Array
{
public : 
	Array(int size);
    ~Array(void);
    
    bool SetData(int pos,T data);
    bool GetData(int pos,T data);
private :
	T *pData;
    int maxsize;
}

클래스의 멤버함수를 정의하는 부분에도 다음과 같이 일일이 template, typename등을 써줘야한다.
그리고 한가지 중요한것은 클래스 템플릿을 정의할때는 멤버함수를 정의하는 부분까지 모두 헤더파일에 적는다는 것이다.

클래스 템플릿도 실제 동작하는 클래스를 찍어내기 위한 틀의 역할이다.
컴파일러가 실제 동작하는 클래스를 만들어내기 위해서는 클래스 템플릿 선언부뿐만 아니라 멤버함수가 어떠헥 정의되어 있는지도 다 알아야하기 때문에 모든 내용을 헤더파일에 적는다.

template<typename T>
Array<T>::Array(int size)
{
	maxsize = size;
    pData = new T[maxsize];
}

template<typename T>
Array<T>::~Array(int size)
{
	delete [] pData;
}

template<typename T>
bool Array<T>::SetData(int pos, T data)
{
	if(pos < 0 || pos >= maxsize)
    	return false;
    pData[pos] = data;
    return true
}

template<typename T>
bool Array<T>::GetData(int pos, T &data)
{
	if(pos < 0 || pos >= maxsize)
    	return false;
    data = pData[pos[;
    return true;

}

클래스 템플릿의 인스턴스화

함수 템플릿으 인트턴스화 할 때는 함수를 호출할 때 사용된 인자의 타입에 따라 typename이 어떤 타입으로 변환되어 인스턴스화 될 지가 결정되지만, 클래스 템플릿을 인스턴스화 할 때는 typename이 어떤 타입으로 변환될지를 명시적으로 지정해줘야한다.

int main(void)
{
	Array <double>data(10);
    '''
}

0개의 댓글