template
- C++에서는 template라는 이름으로 원하는 자료형에 따라 코드가 나오는 틀을 만들 수 있다.
template<typename T>
- 위 선언 아래에 정의되는 클래스에 대해 템플릿을 정의하는 코드
- 템플릿 인자로 T를 받게 되며, T는 반드시 타입 이름임을 명시하고 있다.
- 만약 밑에 오는 것이 함수일 경우 함수에 대한 템플릿이 된다.
- 참고
- template<class T>
- 라고 쓰는 경우도 있지만, typename T와 동일
- 정의한 템플릿의 인자에 값을 전달하기 위해서는
MyTemplate<int> intTemplate;
- 와 같이 <>안에 전달하려는 것을 명시
- 클래스 템플릿에 인자를 전달해서 실제 코드를 생성하는 것을
- 클래스 템플릿 인스턴스화(class template instantiation)라고 한다.
- 템플릿이 인스턴스화 되지 않고 덩그러니 있다면 컴파일 시 아무런 코드로 변환되지 않음
- 반드시 인스턴스화 되어야지만 비로소 컴파일러가 실제 코드를 생성
템플릿 특수화(template specialization)
- bool 자료형은 1개 비트로 충분히 저장할 수 있지만 C++에서 기본로 처리하는 단위가 1byte라서 메모리 낭비가 발생
- 일부 경우에 대해서 따로 처리할 수 있어야함
- 이것이 템플릿 특수화
template<typename A, typename B, typename C>
class test {};
- 위와 같은 클래스 템플릿이 정의되어 있을 때 A가 int고 C가 double일 때 처리하고 싶다면
template<typename B>
class test<int, B, double> {};
- 위와 같이 특수화 하고 싶은 부분에 원하는 타입을 전달하고 위에는 일반적인 템플릿을 사용
- B조차도 특수화 하고 싶다면
template<>
class test<int, int, double> {};
- 와 같이 써주면 된다.
- 이때 주의할 점은 전달할려는 템플릿 인자가 없더라도 특수화 하고 싶다면 template<>라도 남겨야한다.
함수 템플릿(Function template)
#include <iostream>
#include <string>
template<typename T>
T max(T& a, T& b)
{
return a > b ? a : b;
}
int main()
{
int a = 1;
int b = 2;
std::cout << "Max (" << a << "," << b << ") ? : " << max(a, b) << std::endl;
std::string s = "hello";
std::string t = "world";
std::cout << "Max (" << s << "," << b << ") ? : " << max(s, t) << std::endl;
}
output
Max (1,2) ? : 2
Max (hello,world) ? : world
- 템플릿 함수가 인스턴스화 되는 부분은 max(a, b)가 호출되는 부분
- 클래스를 인스턴스화 했을 때와는 다르게 <>하는 부분이 없음
- 템플릿으로 발생되는 오류는 프로그램이 실행되었을 때가 아니라 컴파일 할 때 발생
- 컴파일 시 모든 템플릿을 실제 코드로 변환하여 실행하기 때문
- 컴파일 시에 모든 템플릿이 인스턴스화 된다는 사실을 가지고 템플릿 메타프로그래밍을 할 수 있음
함수 객체(Function Object - Functor)의 도입
template<typename Cont, typename Comp>
void bubbleSort(Cont& cont, Comp& comp)
{
for (int i = 0; i < cont.size(); i++) {
for (int j = i + 1; j < cont.size(); j++) {
if (!comp(cont[i], cont[j])) {
cont.swap(i, j);
}
}
}
}
- 위 함수는 Comp라는 클래스를 템플릿 인자로 받고, 함수 자체도 Comp 객체를 따로 받는다.
- comp객체는 ()연산자 오버로딩을 통해 내부에서 크기 비교를 수행
- comp객체는 함수인양 사용된다.
- 함수는 아니지만 함수인 척을 하는 객체를 함수 객체(Function Object) 줄여서 Functor라고 부름
- 실제 표준라이브러리의 sort 함수도 사용하는 방법
타입이 아닌 템플릿 인자(non-type template arguments)
- 템플릿 인자로 타입만 받을 수 있는 것이 아니다.template의 인자로 T를 받고, 추가적으로 마치 함수의 인자 처럼 int num을 받고 있다.
- 해당 템플릿의 인자들은 addNum 함수를 호출할 때 <>를 통해 전달하는 인자들이 들어감
- 템플릿 인자로 전달할 수 있는 타입을 제한적
- 정수 타입들 (bool, char, int, long 등). float, double은 제외
- 포인터 타입
- enum 타입
- std::nullptr_t (널 포인터)
- 컴파일 타임에 값들이 정해져야 하는 것들이 있을 때 템플릿 인자를 가장 많이 활용
- 배열의 가장 큰 문제점은 함수에 배열을 전달할 때 배열의 크기에 대한 정보를 잃어버린다.
- 하지만 템플릿 인자로 배열의 크기를 명시하면 이 문제를 해결할 수 있음
- 위 예는 STL의 array를 통해 알아볼 수 있다.
#include <iostream>
#include <array>
int main()
{
std::array<int, 5> arr{1, 2, 3, 4, 5};
for (int i = 0; i < arr.size(); i++) {
std::cout << arr[i] << " ";
}
std::cout << std::endl;
}
디폴트 템플릿 인자
- 템플릿도 함수와 마찬가지로 디폴트 인자를 지정할 수 있다.
#include <iostream>
template<typename T, int num = 5>
T addNum(T t)
{
return t + num;
}
int main()
{
int x = 3;
std::cout << "x : " << addNum(x) << std::endl;
}
output
x : 8
- 템플릿 디폴트 인자는 함수 디폴트 인자와 똑같이 인자 뒤에 = (디폴트 값)을 넣어준다.
- addNum(x)는 addNum<int, 5>(x)와 동일함
출처
'C++' 카테고리의 다른 글
[C++] 예외처리 (0) | 2024.12.18 |
---|---|
[C++] 가변 길이 템플릿 (1) | 2024.12.17 |
[C++] 가상 상속 (0) | 2024.12.17 |
[C++] explicit와 mutable (0) | 2024.12.16 |
[C++] 참조자 (0) | 2024.12.16 |