3 분 소요

템플릿 타입 추론

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)

댓글남기기