[열혈 C++] Chap13: 템플릿1
1. 템플릿 이해하기
- 모형자 : 모양을 그릴 때 쓰는 것
- 함수 템플릿 : 함수를 만드는 도구. 함수의 기능은 결정되어 있지만, 자료형은 결정되어 있지 않아서 결정해야한다.
template <typename T> //아래 함수를 템플릿으로 정의한다는 의미
//template <class T> 라고 해도 된다
T Add(T num1, T num2){
return num1 + num2;
}
- 자료형을 결정짓지 않았다. 나중에 T를 대신하여 실제 자료형을 결정한다
- 위 템플릿으로 아래와 같이 사용할 수 있다
template<typename T>
T Add(T num1, T num2){
return num1 + num2;
}
int main(void){
cout << Add<int>(15,20) << endl;
cout << Add<double>(1.5, 2.3) << endl;
cout << Add<int>(20,20) << endl;
return 0;
}
- 자료형을 적용한 함수를 컴파일러가 한번 정의하게 되면 그 다음에는 새로 함수를 만들지 않고 앞서 만들어 놓은 함수를 다시 호출한다.
```cpp
template<typename T>
T Add(T num1, T num2){
return num1 + num2;
}
int main(void){
cout << Add(15,20) << endl;
cout << Add(1.5, 2.3) << endl;
cout << Add(20,20) << endl;
return 0;
}
``` + 이렇게 해도 컴파일러가 알아서 결정해준다
✏️함수 템플릿, 템플릿 함수
- 함수 템플릿
template<typename T> T Add(T num1, T num2){ return num1 + num2; }
- 템플릿 함수 : 템플릿 기반으로 컴파일러가 만들어낸 함수
int Add<int>(int num1, int num2){ return num1 + num2; }
✏️둘 이상의 형에 대한 템플릿
- 이런 것도 됨
template <class T1, class T2> //typename대신 class 사용
void ShowData(double num){
cout << (T1)num << ", " << (T2)num << endl;
//형 변환문 -> (int)67.2 : 67.2를 정수형으로 변환
}
int main(void){
ShowData<char, int>(65);
ShowData<char, int>(67);
ShowData<char, double>(68.9);
ShowData<short, double>(67.2);
ShowData<short, double>(69.4);
return 0;
}
/*실행결과
A, 65
C, 67
D, 68.9
67, 67.2
69, 69.4
*/
✏️함수 템플릿의 특수화
```cpp
#include <iostream>
using namespace std;
template <typename T>
T Max(T a, T b)
{
return a > b ? 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;
return 0;
}
```
위의 함수 템플릿은 인자로 전달된 두 데이터 중 더 큰 값을 반환하는데, 문자열의 경우 단순히 주소값이 비교되는 것이라 아무런 의미가 없다.
길이비교가 목적이라면 `strlen`을 써주거나, 사전순이 목적이라면 `strcmp`로 구성하는 것이 의미가 있다
상황에 따라서 템플릿 함수 구성 방법에 예외를 둘 필요가 있는데 이것이 함수 템플릿의 특수화이다.
#include <iostream>
#include <cstring>
using namespace std;
template <typename T>
T Max(T a, T b)
{
return a > b ? a : b ;
}
template <> //char* 형은 개발자가 제시하고 있으므로, 컴파일러는 함수를 별도로 만들지 않고 이 함수를 호출한다
char* Max(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 strcmp(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;
}
2. 클래스 템플릿
- 필요한 이유
- 제공되는 기능과 내부 행동이 동일하지만, 저장의 대상이 다르다는 이유만으로 유사한 클래스를 여러개 정의하는 것은 비효율적이기 때문
- 클래스 템플릿 정의
- 함수 템플릿과 동일하다
#include <iostream> using namespace std; template <typename T> class Point { private: T xpos, ypos; public: Point(T x=0, T y=0) : xpos(x), ypos(y) { } void ShowPosition() const { cout<<'['<<xpos<<", "<<ypos<<']'<<endl; } }; int main(void) { Point<int> pos1(3, 4); pos1.ShowPosition(); Point<double> pos2(2.4, 3.6); pos2.ShowPosition(); Point<char> pos3('P', 'F'); // 좌표정보를 문자로 표시하는 상황의 표현 pos3.ShowPosition(); return 0; }
- 템플릿 함수와는 다르게 자료형을 꼭 명시해주어야 한다.
- 함수 템플릿과 동일하다
✏️클래스 템플릿 선언과 정의 분리
#include <iostream>
using namespace std;
template <typename T>
class Point
{
private:
T xpos, ypos;
public:
Point(T x=0, T y=0);
void ShowPosition() const;
};
template <typename T>
Point<T>::Point(T x, T y) : xpos(x), ypos(y)
{ }
template <typename T>
void Point<T>::ShowPosition() const
{
cout<<'['<<xpos<<", "<<ypos<<']'<<endl;
}
int main(void)
{
Point<int> pos1(3, 4);
pos1.ShowPosition();
Point<double> pos2(2.4, 3.6);
pos2.ShowPosition();
Point<char> pos3('P', 'F'); // 좌표정보를 문자로 표시하는 상황의 표현
pos3.ShowPosition();
return 0;
}
❗중요한것은 헤더파일과 cpp파일, main파일을 나눌 때,
1) 클래스 템플릿의 정의는 헤더파일에 모두 넣거나
2) main에 헤더파일과 cpp파일을 모두 include 시켜주어야한다.
- 컴파일러는 파일단위로 컴파일하기 때문에 서로 다른 파일의 내용을 참조하지 않는다.