15) Template
일단 Template가 뭔지 알아보기 이전에, 파이썬에는 없는 템플릿이라는 기능이 왜 C++에서 필요한지 알아보도록 하겠씁니다.
15-1. 파이썬과 C++의 타입
파이썬은 Dynamic typed language 입니다.
파이썬 interpreter가 코드 실행 중에 타입을 체크하는 방식이기 때문에
변수의 타입이 변화되는 것을 허용합니다.
그리고, 파이썬은 Duck typing도 지원하기 때문에 매우 문법이 편리합니다.
- Duck typing : With normal typing, suitability is determined by an object’s type. In duck typing, an object’s suitability is determined by the presence of certain methods and properties
즉, ‘이 타입이 맞는지’ 를 판단하는게 아니라, ‘이 메서드가 있는지’ 를 판단하기 때문에 코드 작성에는 타입에 제한을 받지 않는다는 점입니다.
(물론 디버깅은 그만큼 힘들다는 단점이 있습니다..)
반대로 C++은 Statically typed language입니다.
C++ 컴파일러가 코드 컴파일 중에 타입을 고정해놓는 방식이기 때문에
코드 작성은 불편하지만, 속도 측면에서는 Dynamic type보다 빠릅니다.
(비슷하게, virtual 키워드를 사용해서 포인터의 타입을 동적으로 인식할 수도 있지만, 속도가 상대적으로 느려집니다.)
15-2. Template 기능의 필요성
예를 들어 봅시다.
C++에서 클래스를 만들고 싶은데, 클래스의 특정 멤버변수를 string형으로도 받고 싶고, int형으로도 받고 싶다면 어떻게 해야 할까요??
일반적으로는 그렇게 할 수는 없기 때문에 string만 받는 클래스와 int만 받는 클래스, 두 가지를 전부 작성하는게 맞습니다.
그러면 코드가 중복되기 때문에 매우 불편합니다.
이러한 점을 극복하기 위해서 Template라는 개념이 생겨났습니다.
Template는 매개변수의 타입에 따라서 함수나 클래스를 생성하는 방식입니다.
15-3. 함수 템플릿
함수 템플릿의 문법은 다음과 같습니다.
template <typename 변수이름>
함수 원형 {
// 함수의 본체
}
template <typename 변수이름>
이 추가된 것 말고는 딱히 달라진 게 없습니다.
물론, template <typename T1, T2>
이런식으로 여러 타입을 지정할 수도 있습니다.
예를 들어서, 두 변수의 값을 바꾸는 프로그램은 다음과 같이 작성할 수 있습니다.
ex) 변수의 값을 바꾸는 함수
template <typename T>
void swap(T &a, T &b) {
T temp = a;
a = b;
b = temp;
}
int main(){
int a = 5, b = 10;
double c = 1.5, d = 2.5;
swap(a,b); // swap(int, int)을 저장함.
swap(c,d); // swap(double, double)을 저장함.
std::cout << a << " " << b << std::endl; // 10 5
std::cout << c << " " << d << std::endl; // 2.5 1.5
}
사용 예시를 보면 마치 T라는 데이터 타입이 마치 변수처럼 취급된 느낌입니다.
템플릿 함수는, 모든 타입의 인풋에 대해서 대비하는게 아니라,
int형이 호출되면, int형에 대한 함수를 메모리에 저장하고
double형이 호출되면 double형에 대한 함수를 메모리에 저장하는 방식으로 운용됩니다.
15-4. 특수화(explicit specialization)
그런데, double형에 대해서는 템플릿 함수를 좀 특별하게 만들고 싶으면 어떻게 해야 할까요?
=> double형에 대해서는 명시적으로 함수를 정의해 주어야 합니다.
ex) double형에 대해서는 아무것도 하지 않는 함수를 추가.
template <> void swap(double &a, double &b){
}
15-5. 클래스 템플릿
-
정의 방식은 함수 템플릿과 비슷하게
template <typename 변수이름>
만 앞에 정의하면 됩니다.template <typename T> class Obj{ private: T obj_; public: Obj(T obj){ obj_ = obj; std::cout << obj_ << std::endl; }; };
-
호출 방식은 함수 템플릿과는 약간 다르게, 타입을 지정해줘야 합니다.
int main(){ Obj<double> db_obj(1.5); Obj<int> int_obj(5); }
-
물론, 클래스 내부에 템플릿 함수나, 템플릿 클래스를 작성할 수도 있습니다.