템플릿은 다양한 자료형의 함수를 만들어 낼 수 있는 c++의 문법적 요소이다.

일반적으로, 템플릿은 함수의 기능은 동일하지만 매개변수의 자료형이나 반환형이 다른 경우 활용될 수 있다.

템플릿은 아래와 같은 형식으로 정의된다. 이와 같은 정의를 **함수 템플릿(function template)**이라 한다.

 
template <typename T> //T라는 이름을 이용해서 아래의 함수를 템플릿으로 정의한다는 뜻
T Add(T num1, T num2)
{
	return (num1 + num2);
}
 

위 예제에서 template <typename T> 대신 template <class T>를 사용해도 된다.

어떠한 자료형으로 함수를 만들어달라는 요청이 있을 경우, 컴파일러는 함수 템플릿을 기반으로 새로운 함수를 만들어낸다. 이를 템플릿 함수(template function), 또는 **생성된 함수(generated function)**이라고 한다.

 
int Add<int>(int num1, int num2)
{
	return (num1 + num2);
}
 
double Add<double>(double num1, double num2)
{
	return (num1 + num2);
}
 

위의 템플릿 함수의 표시에서 <int><double>은 일반 함수가 아닌, 컴파일러가 만들어낸 템플릿 기반의 함수임을 표시한 것이다.

위의 예제에서 정의된 템플릿은 아래와 같이 사용될 수 있다.

 
/*AddFunctionTemplate.cpp*/
 
#include <iostream>
using namespace std;
 
template <typename T>
T Add(T num1, T num2)
{
	return (num1 + num2);
}
 
int main(void)
{
	cout<<Add<int>(15, 20)<<endl; //T를 int로 해서 만들어진 Add 함수를 호출한다.
	cout<<Add<double>(2.9, 3.7)<<endl; //T를 double로 해서 만들어진 Add 함수를 호출한다.
	cout<<Add<int>(3.2, 3.2)<<endl; //T를 int로 하도록 정의하였기 때문에 double 형인 입력값이 int로 형변환됨
	cout<<Add<double>(3.14, 2.75)<<endl;
 
	return (0);
}
 

템플릿으로 함수를 호출할 때, 자료형에 기반하여 함수를 만드는 것은 컴파일러의 역할이며, 따라서 컴파일 속도의 감소가 발생한다. 그런데 이는 컴파일 시간의 감소이지 실행 속도의 감소가 아니기 때문에 크게 신경쓸 부분이 아니다.


템플릿을 사용하여 함수를 호출할 때, <> 부분을 생략하여 호출할 수도 있다. 이 경우, 전달되는 인자의 자료형을 참조하여 호출될 함수의 유형을 컴파일러가 결정하기 때문이다.

 
int main(void)
{
	cout<<Add(15, 20)<<endl;
	cout<<Add(2.9, 3.7)<<endl;
	cout<<Add(3.2, 3.2)<<endl;
	cout<<Add(3.14, 2.75)<<endl;
 
	return (0);
}
 

템플릿 함수는 일반 함수와 구분이 되기 때문에 동일한 함수명을 가진 템플릿 함수와 일반 함수가 공존할 수 있으며, 이 경우 함수가 호출되었을 때 일반 함수가 우선권을 가지어 호출된다. 물론 이런 경우가 바람직하지는 못하다.

 
#include <iostream>
using namespace std;
 
template <typename T>
T Add(T num1, T num2)
{
	cout<<"T Add(T num1, T num2)"<<endl;
	return (num1 + num2);
}
 
int Add(int num1, int num2)
{
	cout<<"Add(int num1, int num2)"<<endl;
	return (num1 + num2);
}
 
double Add(double num1, double num2)
{
	cout<<"Add(double num1, double num2)"<<endl;
	return (num1 + num2);
}
 
int main(void)
{
	//기본적으로는 일반 함수가 우선권을 가지어 호출된다.
	cout<<Add(5, 7)<<endl;
	cout<<Add(3.7, 7.5)<<endl;
	//하지만 <>을 이용해 함수가 템플릿 함수임을 명시하면 템플릿 함수가 호출된다.
	cout<<Add<int>(5, 7)<<endl;
	cout<<Add<double>(3.7, 7.5)<<ednl;
}
 

다음과 같이 복수의 자료형을 사용하여 함수 템플릿, 템플릿 함수를 정의할 수 있다.

 
#include <iostream>
using namespace std;
 
template <class T1, class T2>
void ShowData(double num)
{
	cout<<(T1)num<<", "<<(T2)num<<endl;
}
 
int main(void)
{
	ShowData<char, int>(65);
	ShowData<char, int>(67);
	ShowData<char, double>(68.9);
	ShowData<short, double>(69.2);
	ShowData<short, double>(70.4);
	return (0);
}
 

참고로, 위 예제의 7행은 다음의 문장으로 대체할 수 있다.

cout<<T1(num)<<", "<<T2(num)<<endl;

이렇듯 c++에서는 데이터에 소괄호를 묶는 형태로 형 변환을 명령할 수 있다. 즉, 다음의 형 변환문은

int num = (int)3.14;

다음의 형 변환문과 완전히 일치한다.

int num = int(3.14);


특정 자료형에 한하여 템플릿 함수의 구성방법에 예외를 두어 구현하는 것을 함수 템플릿의 특수화라고 한다.

함수 템플릿의 정의 후 template <> 키워드를 사용하여 정의한다.

 
/*SpecialFunctionTemplate.cpp*/
 
#include <iostream>
#include <cstring>
using namespace std;
 
template <typename T>
T Max(T a, T b)
{
	return (a > b ? a : b);
}
 
template <>
char *Max<char *>(char *a, char *b) //특수화하는 자료형을 명시
{
	cout<<"char *Max<char *>(char *a, char *b)"<<endl;
	return (strlen(a) > strlen(b) ? a : b);
}
 
template <>
const char *Max(const char *a, const char *b) //특수화하는 자료형을 생략
{
	cout<<"const char *Max<const char *>(const char *a, const char *b)"<<endl;
	return (strcpm(a, b) > 0 ? a : b);
}
 
int main(void)
{
	cout<<Max(11, 15)<<endl;
	cout<<Max('T', 'Q')<<endl;
	cout<<Max(3.5, 7.5)<<endl;
	cout<<Max("Simple", "Best")<<endl;
 
	char str1[] = "Simple";
	char str2[] = "Best";
	cout<<Max(str1, str2)<<endl;
 
	return(0);
}
 

템플릿과 static

함수 템플릿 내에 static 지역변수가 존재하고 이 지역변수의 자료형이 정의되지 않았을 경우, 템플릿 함수가 생성될 때마다 static 지역변수 또한 별개로 생성된다.

 
template <typename T>
void ShowStaticValue(void)
{
	static T num = 0;
	num += 1;
	cout<<num<<" ";
}
 

참고자료

윤성우의_열혈_cpp_프로그래밍