지난번에 Swap() 함수를 이용하여 두 인자를 교환하는 코드를 만든 적이 있다. 이 인자가 int였는데, 만약 double형으로 바꾸고 싶다면 어떻게 할까? double형으로 오버로딩하는 방법이 있을 것이다. 하지만 단순히 그런 거 때문에 오버로딩 하는 것보다 더 좋은 방법이 있다. 바로 함수 템플릿을 쓰는 것이다.
template <typename T>
void Swap(T & a, T & b)
{
T temp;
temp = a;
a = b;
b = temp;
}
typename 대신에 class를 써도 된다. T는 그냥 아무 이름이나 쓴건데, "T라는 자료형을 쓸 것이다~"라고 말하는 것이다. 보통 T,U,V 순으로 쓴다. 저 구문 바로 밑에 함수를 만들어 주어야 하고, 임의로 넣을 자료형을 T로 지칭하면 된다. 그리고 함수를 사용하면, 컴파일러가 알맞게 자료형을 변환해서 넣어준다.
int a = 5, b = 10;
double c = 8.0, d = 12.5;
Swap(a, b) // T는 int형으로 변환될 것이다.
Swap(c, d) // T는 double형으로 변환될 것이다.
일반적으로 템플릿은 메인 함수 밖에다가 적는다. 그리고 모든 매개변수를 템플릿으로 적을 필요는 없다.
템플릿은 구체적인 데이터형이 아니라, 어느 것도 적용 가능하므로 '일반화 프로그래밍'이라고도 한다. 또한 데이터형이 매개변수에 의해 표현되므로, '매개변수화 데이터형'이라고도 한다.
template<typename T>
void f(T a, T b)
{
if (a > b)
...
}
여기서 매개변수로 구조체나 배열을 넣을 수 있겠는가? 구조체는 크고 작음을 비교할 수도 없고, 배열은 주소를 비교하기 때문에 개발자의 의도와는 다르게 작동할 수 있다. 이 문제를 어떻게 해결할 것인가? 연산자를 오버로딩 하는 방법(나중에 배운다.)도 있겠지만 여기서는 특화된 템플릿을 정의하는 방법을 배운다. 명시적 특수화의 형식은 다음과 같다.
template <> void Swap<자료형>(자료형& j1, 자료형& j2);
template <> void Swap(자료형& j1, 자료형& j2);
다만 이렇게 쓸 때는, 원본 템플릿 함수가 정의되어 있어야 한다. 그래야지 저 '특정 자료형'이 들어가는 명시적 특수화가 의미가 생기니 말이다. 다음 코드는 자료형을 구조체로 해서 작성해보았다.
template<typename T>
void Swap(T& a, T& b);
struct job
{
char name[40];
double salary;
int floor;
};
template <> void Swap<job>(job& j1, job& j2);
int main()
{
int i = 10, j = 20;
job sue = { "Susan", 73000.60, 7 };
job sidney = { "Sidney", 78060.60, 9 };
Swap(i, j); // 함수 템플릿 사용.
Swap(sue, sidney); // 명시적 특수화 사용.
cout << "i : " << i << ", j : " << j << endl;
cout << "sue.name : " << sue.name << ", sue.salary : " << sue.salary << ", sue.floor : " << sue.floor << endl;
cout << "sidney.name : " << sidney.name << ", sidney.salary : " << sidney.salary << ", sidney.floor : " << sidney.floor << endl;
}
template<typename T>
void Swap(T& a, T& b)
{
T temp = a;
a = b;
b = temp;
}
template <> void Swap<job>(job& j1, job& j2)
{
double t1;
int t2;
t1 = j1.salary;
j1.salary = j2.salary;
j2.salary = t1;
t2 = j1.floor;
j1.floor = j2.floor;
j2.floor = t2;
}
실행 결과.
서로 다른 자료형의 템플릿 매개변수가 2개 있을땐 이런식으로 사용한다.
template<typename T, typename U>
void Swap(T& a, T& b, U& c);
일반적으로 템플릿 함수는 일반 함수보다 우선순위가 낮다. 그러니까 만약 일반 함수에도 적용되고 템플릿 함수에도 적용되는 함수라면, 일반 함수를 택한다는 말이다.