STL을 들어가기 전 마지막 사전 지식인 템플릿에 대해 알아보자
템플릿은 함수나 클래스를 찍어내는 틀을 의미한다
1) 함수 템플릿
2) 클래스 템플릿
이렇게 두 가지 종류로 구분이 된다
이번 시간에는 함수 템플릿을 알아보고
다음 두 번째 시간에는 클래스 템플릿을 알아보도록 하자
그럼 템플릿을 어떻게 사용하는지 알아보기 전,
템플릿이 왜 필요한지 알아보자
void Print(int a){}
void Print(float a){}
void Print(double a){}
void Print(const char* a){}
함수의 인자들의 타입에 맞게 내가 모든 함수를 위처럼 구현해 준다면
너무 귀찮을 것이다
템플릿 사용 방법을 그럼 알아보자
아래처럼 템플릿을 사용하면 훨씬 쉽게 사용이 가능해진다
template <typename T>
void Print(T a){}
아래와 같이,
template <class T>로 사용해도 가능하고
T를 인자 여러 개에 사용해도 되고, T를 반환 타입으로 사용해도 된다
template <typename T>
T Add(T a, T b){}
인자들의 타입을 다르게 해서 만들고 싶다면 아래와 같이 사용하면 된다
template < typename T1, typename T2>
void Print(T1 a, T2 b){}
이렇게 만들어준 템플릿을 메인 함수에서 호출할 때,
암시적으로 생성이 되는 것이 기본이고
명시적으로 생성하려면 타입을 작성해 주면 된다
아래를 통해 알아보자
int main()
{
// 암시적으로 생성
Print(50);
Print(50.0f);
Print(50.0);
Print("Hello World");
// 명시적으로 타입을 골라줌
Print<int>(50);
Print<float>(50.0f);
Print<double>(50.0);
Print<const char*>("Hello World");
int result1 = Add(1, 2);
float result2 = Add<float>(1.1f, 1.2f);
}
그런데...
만약, 우리가 직접 만든 클래스를 템플릿에 적용하면 어떻게 될까?
아래를 통해 한번 시험해 보자
class Knight
{
public:
int _hp = 100;
};
template <typename T>
void Print(T a)
{
cout << a << endl;
}
int main()
{
Knight k1;
Print(k1); // 오류가 발생한다
}
위에서 오류가 발생하는 이유는
Print 함수 구현부에 있는 << 연산자는 클래스 Knight를 지원하지 않기 때문에 오류가 발생한 것이다
그럼 이를 해결하기 위해서
<< 연산자 오버로딩을 우리가 해준다면 해결이 가능해진다
아래와 같이 해결해 보자
class Knight
{
public:
int _hp = 100;
};
template <typename T>
void Print(T a)
{
cout << a << endl;
}
// 연산자 오버로딩 (전역함수 버전)
ostream& operator<<(ostream& os, const Knight& k)
{
os << k._hp;
return os;
}
int main()
{
Knight k1;
Print(k1); // 정상적으로 k._hp가 출력된다
}
그러면 우리가 매번 함수 구현부에 있는 연산자를 오버로딩해줘야 하는가?
당연히 아니다
이를 해결하기 위해 템플릿 특수화를 사용하면 된다
템플릿 특수화란 뭘까?
어떤 타입이든 내부적으로는 같은 규칙으로 실행되기 때문에
특정 타입에 대해서만 다른 규칙을 만들고 싶을 때 사용한다
템플릿 예외 버전을 따로 만들어준다고 생각하면 된다
아래의 예시를 통해 어떻게 만드는지 알아보자
class Knight
{
public:
int _hp = 100;
};
// 우리가 기존에 만들어준 템플릿
template <typename T>
void Print(T a)
{
cout << a << endl;
}
// 템플릿 특수화로 만든 템플릿
template<> // 1. <>사이를 비워둔다
void Print(Knight a) // 2. 예외로 사용할 타입을 받는다
{
cout << a._hp << endl; // 3. 구현해준다
}
int main()
{
Knight k1;
Print(k1); // 템플릿 특수화가 실행이 된다
}
위와 같이 템플릿 특수화를 사용하면 우리가 만들어준 템플릿의
예외 타입에 해당하는 함수 내부를 따로 구현해 줄 수 있다
마지막으로,
함수 템플릿의 주의점에 대해 알아보자
템플릿을 만들었다고 해서 하나의 함수만 만들어지고 실행되는 것이라고 생각할 수 있다
하지만,
어셈블리어로 바꿔서 보면
호출한 타입별 함수들 마다 주소가 다 다르기 때문에
템플릿을 사용했다고 해서 하나의 함수만 만들어진다고 착각해서는 안되고
타입마다 필요한 함수는 다 하나씩 실제로 만들어진다고 생각하면 된다
'C++ > [루키스] 콜백함수' 카테고리의 다른 글
[STL 사전지식] 6. 콜백 함수 (0) | 2023.01.25 |
---|---|
[STL 사전지식] 5. 템플릿 기초 (2) (0) | 2023.01.25 |
[STL 사전지식] 3. 함수 객체 (0) | 2023.01.23 |
[STL 사전지식] 2. 함수 포인터 (2) (0) | 2023.01.22 |
[STL 사전지식] 1. 함수 포인터 (1) (0) | 2023.01.22 |