그냥저냥

[C++] 템플릿 (Template) 본문

공부/이것저것

[C++] 템플릿 (Template)

오양J 2017. 1. 23. 21:41

※ Template


템플릿화한다는 것은 기능은 정해져있지만 자료형은 정해지지않고 구현한다는 것을 의미한다.


template <typename T>

(== template <class T>)


위는 'T라는 이름(type name)에 대해서, 다음에 정의하는 대상을 템플릿으로 선언한다.'를 뜻한다.

위의 선언을 해주고 T라는 typename을 사용하면 된다.


아래는  Add 함수를 템플릿화한 예시이다.

template <typename T>
T Add(T a, T b){
	return a + b;
}

마치 T라는 typename을 int와 double과 같은 자료형처럼 사용하면 된다.




[1] 함수 템플릿


 앞서 Add라는 함수를 템플릿화 하였다. 이를 의미하는 단어는 함수 템플릿이다.

다시말해, 함수 템플릿은 함수를 템플릿화한다는 것을 의미한다.


①  둘 이상의 타입에 대해서 템플릿화하기

 함수의 input 값이 여러개일 때, 각각 다른 자료형을 갖는 경우를 위해서 typename이 필요한 자료형 종류의 수만큼 필요하다.

T1과 T2의 자료형은 같을 수도 있고 다를 수도 있다.

template <typename T1, typename T2>
void Show(T1 a, T2 b){
	cout << a << endl;
        cout << b << endl;
}


② 함수 템플릿의 특수화 (template specialization)

 input으로 들어온 인자가 차지하는 메모리의 크기를 바이트 단위로 리턴하는 함수를 템플릿화하는 예제가 있다.

만약 인자가 문자열을 가리키는 char*인 경우 포인터의 크기 4를 리턴하는 것이 아니라 문자열의 길이를 리턴해주길 원한다.

따라서 char*을 인자로 받는 경우 strlen()함수를 통해 문자열의 길이를 리턴해줘야 한다.

template <typename T>
int SizeOf(T a) {
	return sizeof(a);
}

template<> // 함수 템플릿 특수화 선언
int SizeOf(char* a) {	// 전달 인자가 char*인 경우 이 함수 호출!
	return strlen(a);
}


[2] 클래스 템플릿



① 클래스 템플릿의 정의

클래스를 템플릿화하는 방법은 함수를 템플릿화하는 방법과 유사하다.

하지만 클래스를 정의하고나서 객체를 생성 시 결정하고자 하는 자료형을 명시적으로 선언해 줘야 한다.

template <typename T>
class Data
{
	T data;
public:
	Data(T d) {
		data = d;
	}
	void SetData(T d) {
		data = d;
	}
	T GetData(T d) {
		return data;
	}
};

int main(void)
{
	Data<int> d1(0);
	Data<char> d2('a');
}

객체 생성 순서는 '메모리 공간 할당' > '생성자 호출' 순으로 이루어진다. 생성자가 호출되어야 전달 인자를 참조하여 전달 인자의 자료형을 결정지을 수 있지만,

먼저 메모리 공간 할당을 해야한다. 따라서 명시적으로 T의 자료형을 선언하며 객체를 생성해야 된다.

보다 근본적인 이유는 생성자를 통해서 전달되는 인자의 자료형과 결정되어야 할 템플릿의 자료형이 다를 수도 있다는 것이다.


② 클래스 템플릿의 선언과 정의 분리

아래의 코드는 위의 예시에서 선언과 정의를 분리한 것이다.

template <typename T>
class Data
{
	T data;
public:
	Data(T d);
	void SetData(T d);
	T GetData();
};

template <typename T>
Data<T>::Data(T d) {
	data = d;
}
template <typename T>
Data<T>::SetData(T d) {
	data = d;
}
template <typename T>
T Data<T>::GetData(T d) {
	return data;
}

Data<T>::SetData(...)

위의 선언이 의미하는 것은 T 타입에 대해서 템플릿으로 정의되어 있는 "Data 클래스 템플릿"중 SetData함수의 정의를 쓰겠다는 것이다.

이는 "클래스 템플릿 Data"과 "클래스 Data"는 다르다는 것을 의미한다.


또한 함수 정의에서 한번더 template<typename T> 선언해주고 있다.

선언하고 있는 T가 무엇인지를 보충 설명해주는 역할이다. 멤버 함수를 정의할 때마다 반드시 붙여줘야한다.



[3] 템플릿의 원리 이해



템플릿은 호출이 가능한 함수를 만들기 위한 하나의 틀이다.

함수 템플릿을 만들고 메인함수에서 호출되어 컴파일러에 의해 생성되는 특정 자료형을 갖는 함수를 템플릿 함수라 부른다. 다시 말해, 함수 템플릿을 기반으로 해서 만들어지는, 실제 호출이 가능한 함수들을 가르켜 템플릿 함수라고 부른다.

템플릿을 기반으로 만들어진 함수이기 때문이다.

또한 템플릿 함수가 생성되는 현상을 "함수 템플릿의 인스턴스화(instantiation)" 라고 부른다.


클래스 템플릿 또한 객체화가 가능한 클래스를 만들기 위한 하나의 틀이다.

인스턴스화를 거쳐 생성된 클래스를 템플릿 클래스라 부른다.(자료형이 결정되어 있는 클래스)


이처럼 템플릿을 처리해주는 것은 컴파일러이기 때문에 템플릿 클래스는 선언과 정의를 각각 다른 파일(.h / .cpp)에 분리시켜 놓을 수 없다. 분리된 것의 연관 관계를 찾아주는 것은 링커(linker)가 담당해 주기 때문이다. 따라서 클래스 템플릿은 하나의 파일 내에 선언과 정의가 함께 있어야 한다.



Comments