C++ 템플릿 타입 추론 규칙
템플릿 타입 추론
tempate<typename T>
void f(const T& param);
- 위와 같은 템플릿의 선언이 있다고 하자.
- const T& 이 매개변수 타입이다.
int x = 0;
f(x);
- 위의 코드에서 함수 f의 인수 타입은 int 이고, 매개변수 타입은 const int& 이다. 즉, 템플릿 매개변수 T는 int 로 추론된다.
- T는 인수 타입과 매개변수 타입에 의해 추론된다. 형태에 따라 몇 가지 경우로 나누어 볼 수 있다.
1. 매개변수 타입이 참조 타입이지만 보편 참조는 아닌 경우
- 인수 타입이 참조 타입이면 참조 부분이 무시된다.
- 인수 타입을 매개변수 타입에 대응시켜보면 T의 타입을 결정할 수 있다.
template<typename T>
void f(T& param); // param은 참조 형식
int x = 27; // x 는 int
const int cx = x; // cx 는 const int
const int& rx = x; // rx 는 const int인 x에 대한 참조
f(x); // T 는 int, param의 타입은 int&
f(cx); // T 는 const int, param의 타입은 const int&
f(rx); // T 는 const int, param의 타입은 const int&
- const 성은 T에 대해 연역된 형식의 일부가 된다.
- 참조성은 무시된다.
template<typename T>
void f(const T& param); // param이 const 에 대한 참조
int x = 27; // x 는 int
const int cx = x; // cx 는 const int
const int& rx = x; // rx 는 const int인 x에 대한 참조
f(x); // T는 int, param의 타입은 const int&
f(cx); // T는 int, param의 타입은 const int&
f(rx); // T는 int, param의 타입은 const int&
2. 매개변수 타입이 보편 참조인 경우
- 인수 타입이 lvalue 타입이면 T와 매개변수 타입 모두 lvalue 참조로 추론된다. T가 참조 타입으로 추론되는 경우는 이 경우가 유일하다.
- 매개변수 타입이 rvalue 참조 같은 모습이지만 추론된 형식은 lvalue 참조이다.
- 인수 타입이 rvalue 이면 1번 경우의 규칙들이 적용된다.
template<typename T>
void f(T&& param); // param은 보편 참조
int x = 27; // x 는 int
const int cx = x; // cx 는 const int
const int& rx = x; // rx 는 const int인 x에 대한 참조
f(x); // x 는 lvalue, 따라서 T는 int&, param의 타입 역시 int&
f(cx); // cx 는 lvalue, 따라서 T는 const int&, param의 타입 역시 const int&
f(rx); // rx 는 lvalue, 따라서 T는 const int&, param의 타입 역시 const int&
f(27); // 27은 rvalue, 따라서 T는 int, 그러므로 param의 타입은 int&&
3. 매개변수 타입이 참조가 아닌 경우
- 인수가 값으로 전달되는 상황이다.
- 인수 타입이 참조라도 참조는 무시된다.
- 인수 타입의 const 성도 무시된다. volatile 도 무시된다.
template<typename T>
void f(T param); // param이 값으로 전달된다.
int x = 27; // x 는 int
const int cx = x; // cx 는 const int
const int& rx = x; // rx 는 const int인 x에 대한 참조
f(x); // T와 param의 타입 모두 int
f(cx); // 여전히 T와 param의 타입은 모두 int
f(rx); // 이번에도 T와 param의 타입은 모두 int
4. 배열 인수
- 배열 형식은 포인터 형식과는 다르다.
- 템플릿 함수에 값으로 전달되는 배열의 타입은 포인터 타입으로 추론된다.
template<typename T>
void f(T param); // 값 전달 매개변수가 있는 템플릿
const char name[] = "J. P. Briggs"; // name의 형식은 const char[13]
const char* ptr_to_name = name; // 배열이 포인터로 붕괴한다.
f(name); // name은 배열이지만 T는 const char* 로 추론된다.
template<typename T>
void b(T& param); // 참조 전달 매개변수가 있는 템플릿
b(name); // T는 const char[13]으로 추론되고, 매개변수 타입은 const char (&)[13] 으로 추론된다.
- 이런 특성을 이용하면 배열에 담긴 원소들의 개수를 추론하는 템플릿을 만들 수 있다.
5. 함수 인수
- 배열만 포인터로 붕괴하는 것이 아니고 함수 타입도 함수 포인터로 붕괴될 수 있다.
void some_func(int, double); // some_func는 타입은 void(int, double)
template<typename T>
void f1(T param); // f1의 param은 값 전달 형식
template<typename T>
void f2(T& param); // f2의 param은 참조 전달 방식
f1(some_func); // param은 함수 포인터로 추론됨. 타입은 void (*)(int, double)
f2(some_func); // param은 함수 참조로 추론됨. 타입은 void (&)(int, double)
댓글남기기