C++ 템플릿 마스터하기: 제네릭 프로그래밍 가이드
템플릿(Template)은 제네릭 프로그래밍의 기초로, 특정 타입에 독립적인 방식으로 코드를 작성하는 것을 포함합니다.
템플릿은 제네릭 클래스나 함수를 생성하기 위한 청사진이나 공식입니다. 이터레이터와 알고리즘 같은 라이브러리 컨테이너들은 제네릭 프로그래밍의 예시이며 템플릿 개념으로 개발되었습니다.
예를 들어 vector 같은 각 컨테이너는 단일 정의가 있지만, vector<int>나 vector<string> 등 다양한 종류의 벡터를 정의할 수 있습니다.
함수와 클래스 모두 정의하는 데 템플릿을 사용할 수 있습니다. 어떻게 작동하는지 봅시다.
함수 템플릿
템플릿 함수 정의의 일반적인 형태:
template <class type> ret-type func-name(parameter list) {
// 함수 본문
}
여기서 type은 함수에서 사용되는 데이터 타입의 플레이스홀더 이름입니다. 이 이름은 함수 정의 내에서 사용될 수 있습니다.
두 값 중 최댓값을 반환하는 함수 템플릿 예제:
Live Demo
#include <iostream>
#include <string>
using namespace std;
template <typename T>
inline T const& Max(T const& a, T const& b) {
return a < b ? b : a;
}
int main() {
int i = 39, j = 20;
cout << "Max(i, j): " << Max(i, j) << endl;
double f1 = 13.5, f2 = 20.7;
cout << "Max(f1, f2): " << Max(f1, f2) << endl;
string s1 = "Hello", s2 = "World";
cout << "Max(s1, s2): " << Max(s1, s2) << endl;
return 0;
}
위 코드를 컴파일하고 실행하면:
Max(i, j): 39
Max(f1, f2): 20.7
Max(s1, s2): World
클래스 템플릿
함수 템플릿을 정의할 수 있는 것처럼 클래스 템플릿도 정의할 수 있습니다. 제네릭 클래스 선언의 일반적인 형태:
template <class type> class class-name {
...
}
여기서 type은 클래스 인스턴스화 시 지정될 플레이스홀더 타입 이름입니다. 쉼표로 구분된 리스트를 사용해 둘 이상의 제네릭 데이터 타입을 정의할 수 있습니다.
Stack<> 클래스를 정의하고 스택에서 요소를 푸시/팝하는 제네릭 메서드들을 구현하는 예제:
Live Demo
#include <iostream>
#include <vector>
#include <cstdlib>
#include <string>
#include <stdexcept>
using namespace std;
template <class T>
class Stack {
private:
vector<T> elems; // 요소들
public:
void push(T const&); // 요소 푸시
void pop(); // 요소 팝
T top() const; // 최상위 요소 반환
bool empty() const { // 비었으면 true 반환
return elems.empty();
}
};
template <class T>
void Stack<T>::push(T const& elem) {
// 전달된 요소 복사본 추가
elems.push_back(elem);
}
template <class T>
void Stack<T>::pop() {
if(elems.empty()) {
throw out_of_range("Stack<>::pop(): empty stack");
}
// 마지막 요소 제거
elems.pop_back();
}
template <class T>
T Stack<T>::top() const {
if(elems.empty()) {
throw out_of_range("Stack<>::top(): empty stack");
}
// 마지막 요소 복사본 반환
return elems.back();
}
int main() {
try {
Stack<int> intStack; // int 스택
Stack<string> stringStack; // string 스택
// int 스택 조작
intStack.push(7);
cout << intStack.top() << endl;
// string 스택 조작
stringStack.push("hello");
cout << stringStack.top() << std::endl;
stringStack.pop();
stringStack.pop();
} catch(exception const& ex) {
cerr << "Exception: " << ex.what() << endl;
return -1;
}
}
위 코드를 컴파일하고 실행하면:
7
hello
Exception: Stack<>::pop(): empty stack