본문 바로가기
C++

[C++] 02. STL - 함수 템플릿(function template)

by KIha_Jung 2019. 11. 12.

1. STL이란 무엇인가

STL은 표준 템플릿 라이브러리(Standard Template Library)의 약자이다. 간단히 말하자면 일반적으로 많이 사용되는 자료구조와 알고리즘을 모은 라이브러리이다. 만들어진 역사와 창시자는 다른 곳에서 참고하길 바란다. STL의 약자의 중간에 있는 템플릿이란 단어에 생소할 수 있다. STL을 구성하고 있는 요소이다. C++를 강력하게 사용하기 위해 꼭 필요하다.

 

2. Generic Programming에 대하여

일반적 프로그래밍이라고 이야기 하지만 총칭적 프로그래밍이라는 말이 더 옳다고 한다. 

그럼 같이 C++에서 무엇을 총칭하는지에 대해 생각해보자.

C++언어에서 총칭을 하는 것은 변수의 타입이다. 변수의 타입을 총칭하면 다음과 같은 장점이 있다. 

1) 총칭된 타입을 사용하는 클래스와 함수를 만들 수 있다.

2) 템플릿을 사용하면 타입에 제약을 받지 않는 로직을 구현할 수 있다.

 

3. 함수 템플릿

한줄로 얘기하면, "오버로딩을 사용하지 않고 템플릿을 사용하여 타입에 제약 받지 않는 로직을 만들수 있다."

프로그래밍에서는 코드를 최대한 간단하게, 유지보수가 될 수 있게 짜는 것이 중요하다. 오버로딩은 강력하지만 코드가 길어지고 가독성이 떨어지며 유지보수가 어렵게 된다. 템플릿을 이용하면 간단한 코드를 짤 수 있다. 

#include <iostream>
using namespace std;

template <typename T> 
T Sum(T a, T b) {
	return a + b;
}

int main() {
	int a = 3;
	int b = 2;
	std::cout << "-------int type-------" << std::endl;
	std::cout << "a + b = " << Sum(a, b) << std::endl;

	double c = 3.2;
	double d = 4.3;
	std::cout << "-------double type-------" << std::endl;
	std::cout << "a + b = " << Sum(c, d) << std::endl;
	system("pause");
	return 0;
}

이렇게 템플릿을 사용하여 만든 함수를 함수 템플릿이라고 정의한다. 

하나의 Mat 함수 템플릿을 만들었는데 어떻게 int 형과 double 형을 사용할 수 있을까?

컴파일 과정을 보면 알 수 있다. 컴파일할 때 템플릿으로 만든 것은 템플릿으로 만든 함수를 호출하는 부분에서 평가한다. 컴파일을 할 때 평가하므로 프로그램의 성능을 떨어뜨리지 않는다. 에러가 없다면 관련 코드를 프로그램 코드 영역에서 생성한다. 따라서 템플릿을 많이 사용하면 컴파일 시간이 길어질 수 있고 실행 파일의 크기도 커질 수 있다. 

 

위의 Max 함수 템플릿에서는 문제가 없을까? 아래 코드를 살펴보자.

#include <iostream>
using namespace std;

template <typename T> 
T Sum(T a, T b) {
	return a + b;
}

int main() {
	int a = 3;
	double b = 2.5;
	std::cout << "-------int type-------" << std::endl;
	std::cout << "a + b = " << Sum(a, b) << std::endl;


	system("pause");
	return 0;
}

컴파일러는 파라메터 T를 사용한 함수의 인자 a, b의 타입을 int로 해야 할지, double로 해야 할지 판단할 수 없다. 따라서 컴파일 에러가 발생한다. 어떻게 해결할 수 있을까?

#include <iostream>
using namespace std;

template <typename T1, typename T2> 
T1 Sum(T1 a, T2 b) {
	return a + b;
}

int main() {
	int a = 3;
	double b = 2.5;		
	std::cout << "-------int type-------" << std::endl;
	std::cout << "a + b = " << Sum(a, b) << std::endl;


	system("pause");
	return 0;
}

간단하다. typename을 복수 개 사용하면 해결 가능하다.

하지만 return형을 T1 으로 선언하였기 때문에 한계가 있을 것으로 보이고 다른 자료형을 다루기 때문에 조심히 다루어야 한다. 이것은 어떻게 해결 가능할까?

 

4. 함수 템플릿의 전문화(Specialization)

함수 템플릿의 전문화라는 특별한 상황에 맞는 함수를 만들면 함수 오버로드와 같이 컴파일러가 상황에 맞는 함수를 선택하도록 한다.

#include <iostream>
using namespace std;

template <typename T1, typename T2> 
T1 Sum(T1 a, T2 b) {
	return a + b;
}

template <> 
int Sum(int a, int b) {
	std::cout << "Specialization!!" << std::endl;
	return a + b;
}
int main() {
	int a = 3;
	int b = 2;		
	std::cout << "-------int type-------" << std::endl;
	std::cout << "a + b = " << Sum(a, b) << std::endl;


	system("pause");
	return 0;
}

변수 a,b 의 자료형이 int형일 때 전문화 함수가 호출된다.  전문화 함수의 호출 순서는 다음과 같다.

1) 전문화된 함수와 맞는지 검사하다.

2) 템플릿 함수와 맞는지 검사한다.

3) 일반 함수와 맞는지 검사한다.

 

5. Non-Type 함수 템플릿

#include <iostream>
using namespace std;

template <typename T, char C> void function1(T a) {
	std::cout << "Non type Template : " << C << std::endl;
}

const char k = 'k';
const char m = 'm';
int main() {
	int a = 1;
	function1<int, k>(a);
	function1<int, m>(a);
	system("pause");
	return 0;
}

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

[C++] 01. C++ 과 C언어의 차이점  (0) 2019.11.12

댓글