[문과 코린이의 IT 기록장] C,C++ - 템플릿(Template)에 대한 이해와 함수 템플릿 (함수를 대상으로 템플릿 이해하기, 함수 템플릿과 템플릿 함수, 둘 이상의 형(Type)에 대해 템플릿 선언하기, 함수 ..
[문과 코린이의 IT 기록장] C,C++ - 템플릿(Template)에 대한 이해와 함수 템플릿 (함수를 대상으로 템플릿 이해하기, 함수 템플릿과 템플릿 함수, 둘 이상의 형(Type)에 대해 템플릿 선언하기, 함수 템플릿의 특수화 (Specialization))
1. 함수를 대상으로 템플릿 이해하기
- 함수 템플릿의 특징
: 함수 템플릿은 함수를 만들어 낸다.
: 함수의 기능은 결정되어 있으나, 자료형은 결정되어 있지 않아서 결정해야 한다.
* 즉 다양한 자료형의 함수를 만들어 낼 수 있다.
1 ) 함수
int Add(int num1, int num2)
{
return num1 + num2;
}
- 함수의 기능 : 덧셈
- 함수의 자료형 : int형
2 ) 함수 -> 템플릿 활용
- 이러한 함수를 만들어낼 수 있는 템플릿은 아래와 같이 정의한다.
template <typename T> // T라는 이름을 이용해서 아래의 함수를 템플릿으로 정의하겠다
/* = template <class T> */
T Add(T num1, T num2) // T는 자료형을 결정짓지 않겠다는 의미로 사용
{
return num1 + num2;
}
- 함수의 기능 : 덧셈
- 대상 자료형 : 결정되어 있지 않음
cf ) 함수를 템플릿으로 정의하는 것이, 매 호출마다 함수를 만드는 것은 아니다.
Case 1 )
#include<iostream>
using namespace std;
template <typename T>
T Add(T num1, T num2) {
return num1 + num2;
}
int main() {
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;
cout << Add<double>(3.14, 2.75) << endl;
return 0;
}
2. 함수 템플릿과 템플릿 함수
1) 함수 템플릿
- 위에 설명했던 정의
template <typename T>
T Add(T num1, T num2) {
return num1 + num2;
}
2) 템플릿 함수 (template function)
- 위의 템플릿을 기반으로, 컴파일러가 만들어 내는 다음 유형의 함수들
int Add<int>(int num1, int num2) {
return num1 + num2;
}
double Add<double>(double num1, double num2) {
return num1 + num2;
}
- <int>와 <double>은 일반함수가 아니라, 컴파일러가 만들어내는 템플릿 기반의 함수임.
- 즉 템플릿 함수는 템플릿을 기반으로 만들어진 함수를 의미함.
Case 2 )
#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() {
cout << Add(5, 7) << endl; // 일반함수 호출
cout << Add(3.7, 3.5) << endl; // 일반함수 호출
cout << Add<int>(5, 7) << endl; // 템플릿 함수 호출
cout << Add<double>(3.7, 7.5) << endl; // 템플릿 함수로 호출
return 0;
}
※ 주의점 : 템플릿함수와 일반함수는 구분된다.
3. 둘 이상의 형(Type)에 대해 템플릿 선언하기
Case 3 )
#include<iostream>
using namespace std;
template <class T1, class T2>
// 쉼표(,)를 이용해서 둘 이상의 템플릿 타입을 명시할 수 있음
// typename = class
void ShowData(double num) { // 함수 템플릿의 매개변수도 기본 자료형으로 선언될 수 있음
// 인자로 전달된 num값을, T1과 T2로 명시되는 자료형으로 형 변환해서 출력함
cout << (T1)num << ", " << (T2)num << endl;
/* = cout << T1(num) << ", " << T2(num) << endl; */
}
int main() {
// 위의 함수 템플릿의 매개변수형이 double이기 때문에, 선언되는 인자를 통해서는 T1,T2의 자료형을 결정짓지 못함
// 따라서, 템플릿 함수의 호출형식을 갖추어서 호출해주어야 함.
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;
}
4. 함수 템플릿의 특수화 (Specialization)
Case 4 ) 함수 템플릿에서 문자열 문제
#include<iostream>
using namespace std;
template<typename T>
T Max(T a, T b) {
return a > b ? a : b;
}
int main() {
cout << Max(11, 15) << endl;
cout << Max('T', 'Q') << endl;
cout << Max(3.5, 7.5) << endl;
cout << Max("Simple", "Best") << endl;
return 0;
}
위 코드의 문자열 부분에서 이 코드는 아무런 의미를 갖지 못한다.
cout << Max("Simple", "Best") << endl; // 문자열의 경우에는 결과에 의미를 지니지 못함
코드의 목적이 문자열의 길이비교인지, 사전편찬 순서 비교인지 결정한 후, 템플릿 함수가 구성되어야 의미가 있다.
// 문자열의 길이비교 목적
const char * Max(const char *a, const char *b){
return strlen(a) > strlen(b) ? a : b;
}
// 사전편찬 순서 비교 목적
const char * Max(const char *a, const char *b){
return strcmp(a,b) > 0? a : b;
// strcmp(a,b) : a가 b보다 크면 0보다 큰 수, 같으면 0, 작으면 0보다 작은 수 출력
}
Case 5 ) 함수 템플릿의 특수화 적용
#include<iostream>
using namespace std;
template<typename T>
T Max(T a, T b) {
return a > b ? a : b;
}
/* 함수 템플릿 Max를, char*형에 대해서 특수화 했다. */
// char*형 템플릿 함수가 필요한 경우에는 별도로 만들지 말고, 이것을 써라
template<>
char* Max<char*>(char* a, char* b) {
cout << "char * Max<char*>(char *a, char *b)" << endl;
return strlen(a) > strlen(b) ? a : b;
}
/* 함수 템플릿 Max를, const char*형에 대해서 특수화 했다. */
template<>
const char* Max<const char*>(const char* a, const char* b) {
cout << "const char * Max<const char*>(const char *a, const char *b)" << endl;
return strcmp(a, b) > 0 ? a : b;
}
int main() {
cout << Max(11, 15) << endl;
cout << Max('T', 'Q') << endl;
cout << Max(3.5, 7.5) << endl;
cout << Max("Simple", "Best") << endl;
// 문자열의 선언으로 인해 반환되는 주소 값의 포인터 형은 const char*이다.
ex. 이는 char *a = "Simple"이 될 경우 포인터로 원소 변경을 할 수 없기 때문이다.
char str1[] = "Simple";
char str2[] = "Best";
cout << Max(str1, str2) << endl;
// str1, str2는 변수의 형태로 선언되었다. 따라서 str1,str2의 포인터 형은 char*이다.
// 배열은 배열 원소 변경이 가능하다. ex. str1[0] ='A' (가능)
return 0;
}
* 유의사항 - 아직 공부하고 있는 문과생 코린이가, 정리해서 남겨놓은 정리 및 필기노트입니다. - 정확하지 않거나, 틀린 점이 있을 수 있으니, 유의해서 봐주시면 감사하겠습니다. - 혹시 잘못된 점을 발견하셨다면, 댓글로 친절하게 남겨주시면 감사하겠습니다 :) |