고인물을 지양하는 블로그

C++ Templates _1: Function Templates 본문

C++

C++ Templates _1: Function Templates

yunjaeGong 2019. 9. 7. 00:47
  • Function Templates
  • Class Templates
  • Template Specialization
  • Template Aliases (C++11)
  • Variadic Templates (C++11)
  • Variable Templates (C++14)

 

템플릿은 함수, 클래스 등이 제너릭 타입에서 동작할 수 있도록 하는 기능이다. 템플릿의 장점은 매 type별 명시적 함수 overloading 없이도 정의된 하나의 클래스/함수에서 여러 type에 대응해 동작할 수 있게 하는 데 있다.

 

템플릿은 크게 세 종류로 구분된다: class templates, function templates, variable templates (C++14)

C++11부터 템플릿은 variadic 이거나 non-variadic이다. 이전 템플릿들은 모두 non-variadic 템플릿이다.

 

 ※ variadic template(가변 인자 템플릿)이란?

...더보기

variadic function(가변 인자 함수)인 std::printf처럼 가변 인자를 받을 수 있는 객체들의 템플릿으로, 컴파일 시간에 인스턴스화가 가능하다

https://eli.thegreenplace.net/2014/variadic-templates-in-c/

 

템플릿의 정의는 template 키워드로 시작하고, 템플릿 매개변수 목록이 뒤에 온다.

template <typename T>

 

여기서 템플릿 매개변수 목록은 하나 이상인 템플릿 매개변수를 쉼표로 구분하고, 꺽쇠로 둘러싼 것이다.

 ※ 단, 함수 템플릿을 특수화할 때는 원래 템플릿의 모든 템플릿 매개변수에 인자를 지정해야 한다. 템플릿을 특수화함을 나타내려면 template 키워드 다음에 빈 꺽쇠 괄호 쌍(< >)을 사용한다. 이는 원래 템플릿의 모드 템플릿 매개변수에 인자를 지정할 것임을 나타낸다.(C++ primer p.842)

템플릿 정의하기

// 값이 같으면 0, v1이 더 작으면 -1, v2가 더 작으면 1을 반환한다.
int compare(const string &v1, const string &v2) {
    if(v1 < v2) return -1;
    if(v1 > v2) return 1;
    return 0;
}
    
int compare(const double &v1, const double &v2) {
    if(v1 < v2) return -1;
    if(v1 > v2) return 1;
    return 0;
}

이 함수는 거의 동일한 함수로, 유일한 차이는 매개변수 타입뿐이다.

함수 템플릿

각 인자 타입에 대해 함수를 오버로딩 하기 보다 함수 템플릿을 정의할 수 있다.

템플릿 버전 compare는 다음과 같을 수 있다.

template<typename T>
int compare(const T &v1, const T &v2) {
    if(v1 < v2) return -1;
    if(v1 > v2) return 1;
    return 0;
}
템플릿의 정의는 template 키워드로 시작하고, 템플릿 매개변수 목록이 뒤에 온다.
template <typename T>
여기서 템플릿 매개변수 목록은 하나 이상인 템플릿 매개변수를 쉼표로 구분하고, 꺽쇠로 둘러싼 것이다.

함수 매개변수와 비슷하게, 템플릿 매개변수도 함수 정의에 사용한 타입이나 값을 나타낸다. 

위 예시에서 T라는 타입 매개변수가 선언돼있다. compare 안에서는 그 이름을 사용해 타입을 참조하는데, T에서 나타나는 실제 타입은 compare를 호출 방법에 따라 컴파일 시점에 결정된다.

 

함수 템플릿 인스턴스화하기

함수 템플릿 선언화 호출 후 실제 동작까지 이뤄지는 과정은 다음과 같다.

함수 템플릿 선언 -> 호출 -> 컴파일 시간에 인자 타입을 이용, 템플릿 타입 매개변수 T와 결합한 타입이 무엇인지 결정(deduction)한다.

 

템플릿을 인스턴스화할 때는 해당 템플릿 매개변수 대신 실제 템플릿 인자를 사용해 해당 템플릿의 새 '인스턴스'를 생성한다.

 

std::cout << compare(1,0) << std::endl;
// int compare(int &v1, int &v2) 를 인스턴스화 한다

vector<int> vec1{1,2,3}, vec{4,5,6}
std::cout << compare(1,0) << std::endl;
// int compare(vector<int> &v1, vector<int> &v2) 를 인스턴스화 한다

 

템플릿 타입 매개변수

위에서 예를 든 compare함수에는 타입 매개변수가 하나 있다.

일반적으로 타입 매개변수는 내장(built in) 타입 지정자를 사용할 때와 같은 방식으로 타입 지정자로 사용할 수 있다. 특히 타입 매개변수로 반환 타입이나 함수 매개변수 타입을 명명하거나, 변수를 선언에 사용될 수 있다.
template <typename T, class U> calc (const T&, const U&);

 

비타입 매개변수

비타입 매개변수(none type)는 타입이 아닌 값을 나타내며, class, template 키워드 대신 특정 타입을 지정해 사용한다.

비타입 매개변수 템플릿이 인스턴스화 될 때, 매개변수는 사용자가 지정하거나, 컴파일러가 추론한 값으로 대체된다.

template<unsigned N, unsigned M>
int compare(const char (&p1)[N], const char (&p2)[M]) {
    return strcmp(p1, p2);
}

문자열 상수를 다루는 compare 버전을 예로 들면,

compare("hi","mom");
int compare(const char(&p1)[3], const char(&p2)[4])

위와 같이 인스턴스화 된다.

 

비타입 매개변수는 정수 타입이거나 포인터 또는 객체나 함수 타입에 대한 (l-value)참조자일 수 있다. 비타입 매개변수와 결합된 인자는 반드시 상수 표현식이어야 하고, 포인터나 참조자 비타입 매개변수와 결합한 인자는 반드시 생명 주기가 정적이어야 한다.

 

템플릿 비타입 매개변수는 해당 템플릿 정의 안에서 상수 값이다. 비타입 매개변수는, 예를 들면 배열의 크기를 지정하는 등 상수 표현식이 필요할 때 사용할 수 있다. (C++ primer p.778)

'C++' 카테고리의 다른 글

전처리지시자  (0) 2019.11.19
Comments