본문 바로가기
1_ 맛있는프로그래밍/C and C++

C++ - 템플릿 : 함수 템플릿 정의 하기

by 준환이형님 2011. 1. 24.

잘 쓰지는 않지만 ctr+C,V 를  줄이자면 안 쓸 수도 없는 템플릿~ template <typename T>. 이 짧막한게 써먹으려면 또 잘 안 떠오름..;;


출처 : 최익필의 이름없는 블로그(http://www.ikpil.com/725)

다음 문구는 비야네 스트롭 스트룹의 "The C++ Programming Language"의 13장, 템플릿의 처음 부분의 것을 인용한 것이다.

" '개념(concept)'이라 하는 것은 그 자체의 독립성이 보장될 때는 독립적으로 표현되어야 마땅하며, 다른 개념과 결합시키려면 나음대로의 합당한 이유가 있어야 한다. 이것은 원칙이며, 이 것이 깨진다면, 이상한 개념들의 뭉치와 불필요한 의존구조만이 난무한 산업폐기물만이 하나 더 추가 될 뿐이다. "


또한 다음과 같이 마무리 한다.


" 독립과 결합, 이 두 가지를 어떻게 선택하든지 둘 중 하나라도 지키지 않으면, 소프트웨어 구성에 필요한 구성요소를 선택하는 데 있어서 상당 부분의 융통성을 잃게 된다는 것을 확실하다. C++ 에는 이런 문제에 대한 해결책을 가지고 있는데, 그것이 바로 '템플릿" 이다"


즉, C++ 의 템플릿은 개념의 독립적 사용과 결합을 위하여, 사용 될 수 있는 막강한 무기 말하는 것이다.


"템플릿은 자신에게 주어진 매개변수 타입만으로 자신의 동작 대상을 결정하며, 인자로 넘겨지는 타입 사이의 어떤 관계도 요구하지 않는다."


이 이야기가 바로, 개념들의 결합이 개념들의 독립 기반 위에 결합이 되므로써, 개념이 뒤엉키는 문제점의 해결책으로 템플릿 이 좋다는 것이다. .. .. 역시 이론은 재미없고 지루하며, 하품만 연달아 나오게 한다.

그래도 무시 할 수 없는게 이론이기에, 짚고 넘어간다.


이번엔 템플릿의 기본 문법을 알아 보자. 템플릿은 C++ 에 종속적인 언어이기 때문에, C++ 속에서 사용 될 수 있다. C++ 중에서 클래스, 구조체, 그리고 함수에서 템플릿이 사용 될 될 수 있다. 이 중에서 구조체와 클래스는 그 차이가 없으니, 클래스로 말을 줄이고, 우선 함수에서의 템플릿을 먼저 설명한다.


함수에서의 템플릿 문법

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <iostream>
  
// 함수에서의 템플릿 예제
template <typename T>     /// <-- 여기부터 템플릿 시작 라인
T f( T t )                         /// 여기부터
{       
    return t;                       // 여기까지가 템플릿 변수 T에 대해서 유효하다.
}                                       // 템플릿 종료 라인
  
  
int main( void )
{
    // 컴파일러에게 각 인자를 해석하게 하는 방법으로 실행
    // 함수의 인자값에 의해서 자동으로 타입이 판별되어 T의 타입을 유추한다.
    std::cout << f( 1 ) << std::endl;                       
    std::cout << f( 1.000 ) << std::endl;
    std::cout << f( 'a' ) << std::endl;
    std::cout << f( "안녕 템플릿" ) << std::endl;    
  
    // 컴파일러에게 명시적으로 해석하게 하는 방법으로 실행
    // 명시적으로 타입을 지정하여, 
    std::cout << f<int>( 1 ) << std::endl;
    std::cout << f<double>( 1.000 ) << std::endl;
    std::cout << f<char>( 'a' ) << std::endl;
    std::cout << f<char*>( "안녕 템플릿" ) << std::endl;   
}

4 라인이 바로 "다음부터 나오는 것들은 템플릿을 사용 할거야" 라고 지정하는 것이다. 그 키워드가 template 이며, <> <-- 가 매개변수 이다. 함수를 예로 들자면, () 와 똑같다. typename 은 매개변수가 "C++ 의 타입" 이라는 뜻이므로, C++ 에서 쓰이는 모든 타입을 매개변수로 넣을 수 있다.

파트 1에서 설명했던 데로 이해가 될 것이다.

5 라인 부터 ~ 8 라인 까지 템플릿 매개변수를 T 로 사용 될 수 있다. 그래서 5라인의 함수의 반환값이 T 라고 했을때, 컴파일러는 "정해준 타입의 T 로 반환 된다" 라고 알게 된다.

템플릿 구역의 종료는 " } " 에서 끝나게 된다. 이로써 템플릿 함수가 만들어 진 것이다.


잠깐,

템플릿 함수를 만들었다고 해서, 런타임에 다른 기능이 들어 가거나, 부수적인 효과가 들어가는 것은 전혀 없다. 또한 코드의 길이가 줄거나 자동으로 최적화 되어지는 것도 아니다. The C++ Programming Language 참조


템플릿 함수의 호출 방법은 15 라인부터 25 라인에서 나와 있듯이, 두가지가 존재한다. 하나는 컴파일러에게 맞기는 것이고, 다른 하나는 명시적으로 정해 주는 것이다.

템플릿은 컴파일 타임에 명시적으로 컴파일러에게 알려줘야 하는데, 컴파일러가 사용하는 템플릿 파서에 의해서 자동으로 인식 되게 하는것이, 그냥 변수에 넣는 것이다. 이 때 컴파일러에 의해 인자의 타입이 유추되어 T가 결정된다. 그것이 15라인부터 18라인에 나와 있다.


이 방법이 싫다면, 명시적으로 사용 되는 방법인 22라인부터 25라인까지의 사용한 방법이 있다. 이 방법은 < > <-- 를 이용하여, 인자를 직접 전달한다. 이 방법은 컴파일러 방법보다 더 명시했으므로 함수의 매개변수의 타입과 < > <-- 에서 지정한 타입이 다를 경우, 컴파일러 에러가 발생한다.

이때 템플릿 매개변수로 명시적으로 지정해 주었을 때, 들어오는 인자가 묵시적으로 변환 될 수 있다면, 묵시적으로 변환이 이루어져 해당 타입으로 들어 간다.


일반적으로 템플릿 함수는 그 인자값을 컴파일러가 판단하게 하여, 호출 되는 형태를 무척 많이 쓰는데, 컴파일러의 템플릿 파서가 최신의 것이 아니라면, 명시적으로 해야 할 경우도 있으니, 알아야 한다.


잠깐,

템플릿은 10년 전에 도입이 되었지만, 템플릿 파서가 지금에 들어서야, 어느정도 템플릿 문법을 지원해 주기 때문에, 최신의 컴파일러로 테스트 해보는게 좋을 듯 싶다.


질문의 시간

템플릿 함수가 언제 편하게 쓰일까?

C++ 패턴 중에 Template Method Pattern 이 있다. 이... 패턴이 무엇인지 이야기 한다면 길어지니 생략하고, 템플릿과 동일한 말을 쓰듯이, 해당 타입에 대해서 공통적인 일을 하는 함수가 있다면, 모든 타입별로 똑같은 함수를 여러개 "찍어"어야 한다. 그 때 템플릿 함수를 사용 함으로써, 그 찍어내는 일련의 과정을 없앨 수 있다.

즉 "동일한 개념을 행하는 것"을 찍어 낸다. 이 명제 아래 템플릿을 쓸 수 있다.


주로 어떤 방식이 많이 쓰이나?

Boost 라이브러리를 봐도 알 듯이, 거의 묵시적으로 컴파일러가 알아서 유추하는 방법을 많이 쓰인다. .. 왜냐하면 더 편하기 때문이다. 부득이하게 컴파일러가 이 유추를 못하거나, 잘~ 못하게 될 경우, 명시적으로 서야 하는 경우도 있다.

위에서 말한것처럼 더 편한 경우는, 함수의 포인터를 받는 템플릿 함수에서 그 타입을 정해주기 위해서 <> 에, f<void ()( void*, int *) > 로 .. 무지막지하게 써야 할 것이다. 이것을 컴파일러에게 위임한다면 훨씬 편해 질 것이다.

그래서 최신의 컴파일러에 들어있는 최신의 템플릿 파서를 이용해야 마음이 편하다.



typename 말고 class 라는것도 봤는데 무슨 차이가 있나?

class 는 예전에 많이 쓰이는 방법이였다. 표준 STL 만 봐도 전부(?) class 로 표기 했다. 하지만 class 라는 키워드가 C++ 의 클래스와 햇갈려 typename 이 도입되었다. 그래서 typename 을 쓰는게 좋겠으나, 구현상이나 특징상으로 차이가 전혀 없으므로, 프로그래머의 스타일일이다.

... 어느 프로그래머는 사용자 정의 타입을 받는 템플릿의 경우 class 로, 기본 자료형을 받을 경우에는 typename 을 쓴다고 하나, 언제든 유들있게 상대에게 맞춰주면서 해도 무리가 없다.