템플릿 : 함수나 클래스를 찍어내는 틀
- 함수 템플릿
- 클래스 템플릿
- 함수 템플릿
template<typename T>
void Print(T a)
{
cout << a << endl;
}
int main()
{
Print(50);
Print(50.0f);
Print(50.0);
Print("Hello World");
return 0;
}
template<typename T>//꼭 T가 아니어도됨
template<class T> //동일 뜻
을 사용하면
void Print(int a), void Print(float a) 등
각기 다른 버전의 Print 함수가 컴파일될때 생성됨
이때 메인에서
int main()
{
Print<int>(50);
Print(50.0f);
Print(50.0);
Print("Hello World");
return 0;
}
저런식으로 <타입>을 넣게되면 해당 버전으로 호출하게됨
Print<int>(50.0f); 이렇게하면 50.0f 여도 int 버전을 호출
만약
int Add(int a, int b)
{
return a + b;
}
float Add(float a, float b)
{
return a + b;
}
이런 함수를 호출한다고 한다면
template<typename T>
T Add(T a, T b)
{
return a + b;
}
int main()
{
int result = Add(1, 2);
float result2 = Add<float>(1.2f,1.2f);
return 0;
}
이렇게 템플릿을 사용해서 간편하게 할수 있음
또한
인자를 두개 받는데 타입이 서로 다르다고 한다면
template<typename T1, typename T2 >
void Print(T1 a, T2 b)
{
cout << a <<" "<<b<< endl;
}
이렇게하면 a,b가 서로 다른타입이어도 생성됨
class Knight
{
public:
public:
int _hp = 100;
};
template<typename T>
void Print(T a) // 각기 다른 버전의 Print 함수가 컴파일될때 생성됨
{
cout << a << endl;
}
//템플릿 특수화
template<>
void Print(Knight k)
{
cout << "Knight!!!!!" << endl;
cout << k._hp << endl;
}
//연산자 오버로딩(전역함수 버전)
ostream& operator<<(ostream& os, const Knight& knight)
{
os << knight._hp;
return os;
}
int main()
{
Knight k1;
Print(k1);
return 0;
}
그냥 Print 함수에 Knight 클래스를 넣는다고 하면 작동하지 않지만
연산자 오버로딩을 만들게되면 정상적으로 컴파일하게되고
추가로 만약 매개변수에 Knight가 들어왔을때 특별한 함수로 들어오게 하고싶다면 템플릿 특수화를 통해 Knight가 들어왔을때 호출할 수 있는 특별한 함수를 만들어 줄수 있음
클래스 템플릿
typename T(T는 변경가능)을 붙이면 '조커카드'(어떤 타입도 다 넣을 수 있음)
그런데 무조건 typename을 붙여야 하는 것은 아니다.
template<typename T>
class RandomBox
{
public:
T GetRandomData()
{
int idx = rand() % 10;
return _data[idx];
}
public:
T _data[10];
};
int main()
{
srand(static_cast<unsigned int>(time(nullptr)));
RandomBox<int> rb1;
for (int i = 0; i < 10; i++)
{
rb1._data[i] = i;
}
int value1 = rb1.GetRandomData();
cout << value1 << endl;
RandomBox<float> rb2;
for (int i = 0; i < 10; i++)
{
rb2._data[i] = i+0.5f;
}
float value2 = rb2.GetRandomData();
cout << value2 << endl;
return 0;
}
여기서 크기도 미리 정하지 않아도 된다
template<typename T, int SIZE>
class RandomBox
{
public:
T GetRandomData()
{
int idx = rand() % 10;
return _data[idx];
}
public:
T _data[SIZE];
};
이렇게 선언도 가능
template< >안에 들어가는건 [골라줘야 하는 목록] 이라고 볼 수 있음
결국
int main()
{
srand(static_cast<unsigned int>(time(nullptr)));
RandomBox<int, 10> rb1;
for (int i = 0; i < 10; i++)
{
rb1._data[i] = i;
}
int value1 = rb1.GetRandomData();
cout << value1 << endl;
RandomBox<int,20> rb2;
for (int i = 0; i < 20; i++)
{
rb2._data[i] = i+0.5f;
}
int value2 = rb2.GetRandomData();
cout << value2 << endl;
return 0;
}
이렇게 SIZE 부분에 다른숫자가 들어가서 선언되면 저 RandomBox 1과 2는 전혀 다른 클래스로 만들어지게 됨
rb1 = rb2; 가 성립하지 못하게됨
함수 템플릿에 나왔던 것처럼
//템플릿 특수화
template<int SIZE>
class RandomBox<double, SIZE>
{
public:
double GetRandomData()
{
int idx = rand() % 10;
return _data[idx];
}
public:
double _data[SIZE];
};
double 버전이 호출될시 아래 RandomBox 가 실행되는것
댓글