template <typename T>
bool equal(T a, T b) {
return a == b;
}
→ T 타입의 변수 a와 b를 선언하고 a == b를 반환하는 equal 함수를 템플릿으로 정의하였다.
| 용어 | 의미 | 예시 |
|---|---|---|
| 클래스 | 설계도 | class Car { ... } |
| 인스턴스 | 설계도로 만든 실체 | Car myCar; |
| 함수 템플릿 | 함수 설계도 | template <typename T> bool equal(...) |
| 인스턴스화된 함수 | 타입이 채워진 실제 함수 | equal<int>(...) |
template bool equal<int>(int, int);
template bool equal<>(double, double);
template bool equal(char, char);
→ int 타입의 변수 두 개를 받아 비교하는 equal 함수 템플릿을 명시적으로 인스턴스화하였다.
→ double 타입의 변수 두 개를 받아 비교하는 equal 함수 템플릿을 명시적으로 인스턴스화하였다.
→ char 타입의 변수 두 개를 받아 비교하는 equal 함수 템플릿을 명시적으로 인스턴스화하였다.
컴파일러에게
함수를 미리 만들어 두라는 지시
보통 헤더와 소스가 분리된 경우 필요하다. 이 예제에서는 없어도 컴파일은 잘 된다.
클래스를 기반으로 만들어진 '실제 객체'
클래스(class) = 설계도
인스턴스(instance) = 그 설계도로 만든 실제 물건
template <typename T>
bool equal(T a, T b) {
return a == b;
}
→ equal 함수의 설계도
equal(1, 2); // T = int
→ 컴파일러가 T=int인 equal 함수의 실제 구현을 만들어냄
→ equal int 함수의 instanvce
template <typename T>
bool equal(T a, T b) {
return a == b;
}
typename T
→ T는 int, double, char 등 어떤 자료형이든 될 수 있다.
template <typename T> // OK
template <class T> // OK
typename과 class는 둘 다 "타입 매개변수"를 선언하는 키워드이고, 기능은 완전히 동일하다.
그러나 요즘은 typename을 선호하는 경향이 많다. class는 클래스 선언에도 쓰이기 때문에 헷갈릴 수 있기 때문이다.
<>의 유무는 컴파일러가 타입을 추론하는지, 명시하는지에 따라 차이가 있다.
| 형태 | 의미 |
|---|---|
equal<int>(int, int); | int 타입으로 명시적으로 템플릿 인스턴스를 생성합니다. |
equal<>(double, double); | 타입을 컴파일러가 추론하게 합니다. 이 경우, 인자만 보고 T가 double임을 자동 판단합니다. |
equal(char, char); | 이건 사실 템플릿 인스턴스화가 아니라 일반 함수 선언처럼 보이지만, 컴파일러는 이것도 템플릿으로 해석합니다. 단, equal<char>을 암시적으로 인스턴스화합니다. |
대부분의 경우, 컴파일러가 타입을 자동 추론해주므로 안 써도 된다.
template <typename T>
bool equal(T a, T b) {
return a == b;
}
int main() {
// equal(3, 3.5); // ❌ 에러: 타입이 다르므로 T를 추론할 수 없음
equal<double>(3, 3.5); // ✅ double로 명시해주면 OK
}
템플릿 괄호 < > 안에 숫자(정수) 를 넣는 것.
template <int N>
int scale(int value) {
return value * N;
}
→ <3>은 N = 3으로 설정하겠다는 뜻이다.
value = 5니까 return 5 * 3 = 15.
즉, <3>은 N이라는 정수 템플릿 인자에 3을 전달한 것이다.
int scale(double value, int n) {
return value * n;
}
→ 이렇게 작성해도 되는데 왜 template을 쓰는가?
| 일반 함수 | 템플릿 함수 |
|---|---|
| 코드가 작고 단순 | 타입이나 숫자에 따라 자동으로 여러 함수 생성 |
| 변수 값을 받을 수 있음 | 반드시 상수(literal)만 받을 수 있음 |
| 실행은 좀 느릴 수 있음 | 실행 빠름 (컴파일 시 최적화됨) |
| 초보자에게 쉬움 | 에러 복잡하고 사용 어렵기도 함 |
| 상황 | 일반 함수 | 템플릿 함수 |
|---|---|---|
| 사용자가 입력한 값으로 계산할 때 | ✅ | ❌ |
| 타입이 다양하고 코드 재사용하고 싶을 때 | ❌ (중복 많음) | ✅ |
| 코드가 작고 간단해야 할 때 | ✅ | ❌ |
| 속도가 아주 중요한 고정 연산일 때 | ❌ | ✅ |
template <typename T, typename C = std::vector<T>>
T sum1(C c) {
T t = 0;
for (const auto& e : c)
t += e;
return t;
}
→ return type이 T이고, parameter는 C type의 c를 전달받는, sum1 함수 템플릿을 선언하였다. 템플릿 파라미터 C는 기본값으로 std::vector< T >가 설정되어 있다.
template <typename T, typename C = std::vector<T>>
→ sum1 함수 템플릿은 2개의 타입 인자를 가지며,
두 번째 인자 C는 기본적으로 std::vector< T > 타입을 사용한다.
하지만 일반적으로는 컴파일러가 인자를 추론해 주기 때문에 생략 가능하다.