728x90
1. 함수 템플릿 정의
- 다양한 형식에 대해 호출될 수 있는 함수적 동작을 제공한다.
2. 함수 템플릿 예시
template < typename >
T max( T a, T b )
{
// b < a 라면 a를 반환하고, 아니라면 b를 반환한다.
return b < a ? a : b;
}
int main()
{
int i = 42;
std::cout << "max( 7, i ): " << ::max( 7, i ) << std::endl;
double f1 = 3.4;
double f2 = -6.7;
std::cout << "max( f1, f2 ): " << ::max( f1, f2 ) << std::endl;
std::string s1 = "mathematics";
std::string s2 = "math";
std::cout << "max( s1, s2 ): " << ::max( s1, s2 ) << std::endl;
}
/*
출력 결과
max( 7, i ): 43
max( f1, f2 ): 3.4
max( s1, s2 ): mathematics
*/
- typename이라는 키워드는 c++98 표준을 만드는 중 상당히 늦게 도입됐다. 그전에는 형식 파라미터를 키워드 class로 도입해야 했기 때문에 여전히 typename 대신 class를 사용할 수 있다.
- 일반적으로 템플릿은 어떠한 형식이라도 다룰 수 있는 하나의 실체로 컴파일되지는 않는다.
- 대신 템플릿이 사용될 때마다 템플릿에서부터 각 형식에 맞는 실체를 만든다.
- 따라서 max()는 위의 세 가지 형식 int max( int,int), double max(double, double), std::string max(std::string, std::string)에 맞춰 각각 컴파일된다.
- 템플릿 파라미터를 실제 형식으로 바꾸는 작업을 인스턴스화라고 한다.
3. 템플릿 인자 영역
template < typename >
T max( T a, T b );
//...
int main()
{
int i = 10;
const int c = 42;
::max ( i, c ); // T는 int로 연역된다.
::max ( c, c ); // T는 int로 연역된다.
int& ir = i;
::max ( i, ir ); // T는 int로 연역된다.
int arr[4];
::max ( &i, arr ); // T는 int*로 연역된다.
/*오류 발생*/
::max( 4, 7.2 ); // T는 int로도 double로도 연역될 수 있다.
std::string s;
::max( "hello", s ); // T는 char const[6]로도, std::string로도 연역될 수 있다.
/*해결 방법*/
//1. 두 인자가 모두 일치하게 인자를 변환한다.
::max( static_cast< double >( 4 ), 4.2 );
//2. 컴파일러가 형식 연역을 시도하지 않게 T의 형식을 명시한다.
::max< double >( 4, 4.2 );
//3. 파라미터가 다른 형식을 가질 수 있게 명시한다. 다중 템플릿 파라미터
}
- 호출 파라미터를 참조자로 선언하면 사소한 변환도 형식 연역에 적용되지 않는다.
- 같은 템플릿 파라미터 T도 선언된 두 인자의 형식은 완전히 동일해야 한다.
- 호출 파라미터를 값으로 선언하면 형 소실에 해당하는 사소한 변환은 지원한다.
- const나 volatile로 한정한 것은 무시하며, 참조자는 참조된 형식으로 변환하고, 배열이나 함수는 그에 맞는 포인터형으로 바뀐다.
- 템플릿 파라미터 T로 선언된 두 인자에 대해 형 소실이 일어나고 난 후의 형식이 서로 완전히 같아야 한다.
4. 다중 템플릿 파라미터
// 다중 템플릿 파라미터
template < typename T1, typename T2 >
T1 max( T1 a, T2 b )
{
return b < a ? a : b;
}
auto m = ::max( 4, 5.2 );
- 다른 형식을 갖는 두 호출 파라미터를 넘길 수 는 있지만, 반환형이 선언돼야만 한다는 문제가 있다.
- 호출 인자의 순서에 따라 반환형이 바뀌게 된다.
5. 반환형 연역
template< typename T1, typename T2 >
auto max( T1 a, T2 b )
{
return b < a ? : a : b;
}
- c++14에서 부터 어떠한 특정 반환형도 선언하지 않는 방식으로 ( auto 사용 ) 컴파일러가 반환형을 찾아내게 할 수 있다.
6. 기본 템플릿 인자
// 참조자가 반환되지 않도록 std::decay_t<> 사용
template< typename T1, typename T2, typename RT = std::decay_t< decltype( true ? T1() : T2() ) > >
RT max( T1 a, T2 b )
{
return b < a ? a : b;
}
// 반환값의 기본값을 명시하기 위해 std::common_type<> 사용
template< typename T1, typename T2, typename RT = std::common_type_t< T1, T2 > >
RT max ( T1 a, T2 b )
{
return b < a ? a : b;
}
// 기본 인자값을 가지도록
template< typename RT = long, typename T1, typename T2 >
RT max ( T1 a, T2 b )
{
return b < a ? a : b;
}
7. 함수 템플릿 요약
- 함수 템플릿은 다양한 템플릿 인자에 대한 함수 군을 정의한다.
- 템플릿 파라미터에 종속된 함수 파라미터에 인자를 전달하면 함수 템플릿은 템플릿 파라미터 형식을 연역한 수 해당 형식으로 인스턴스화 된다.
- 템플릿 파라미터를 명시적으로 한정 지을 수 있다.
- 템플릿 파라미터에 대해 기본 인자를 정의할 수 있다. 이전 템플릿 파라미터를 사용할 수도 있고, 그 뒤에 기본 인자를 갖지 않는 파라미터가 나올 수도 있다.
- 함수 템플릿을 오버로딩할 수 있다.
- 함수 템플릿을 오버로딩한다면 수정 사항은 템플릿 파라미터를 명시하는 것 정도에 그쳐야 한다.
- 오버로딩한 함수 템플릿을 호출하기 전에 모든 오버로딩 버전을 '볼' 수 있어야 한다.
반응형