서론
이 장은 C++에서 사용되는 Template개념에 대해서 설명한다.
목차
- Template 기본개념
- Class Template
- Template Specialization(템플릿 특수화)
- 함수의 템플릿(Function Template)
- Function Object(Functor)
- Meta Programming
Template 기본개념
함수나 클래스를 개별적으로 다시 작성하지 않아도 여러 자료 형으로 사용할 수 있도록 하게 만들어 놓은 틀
함수 템플릿(Function Template)과 클래스 템플릿(Class Template)으로 나눠진다.
Class Template
전체 코드
// 템플릿 첫 활용
#include <iostream>
#include <string>
template <typename T>
class Vector {
T* data;
int capacity;
int length;
public:
// 생성자
Vector(int n = 1) : data(new T[n]), capacity(n), length(0) {}
// 맨 뒤에 새로운 원소를 추가한다.
void push_back(T s) {
if (capacity <= length) {
T* temp = new T[capacity * 2];
for (int i = 0; i < length; i++) {
temp[i] = data[i];
}
delete[] data;
data = temp;
capacity *= 2;
}
data[length] = s;
length++;
}
// 임의의 위치의 원소에 접근한다.
T operator[](int i) { return data[i]; }
// x 번째 위치한 원소를 제거한다.
void remove(int x) {
for (int i = x + 1; i < length; i++) {
data[i - 1] = data[i];
}
length--;
}
// 현재 벡터의 크기를 구한다.
int size() { return length; }
~Vector() {
if (data) {
delete[] data;
}
}
};
int main() {
// int 를 보관하는 벡터를 만든다.
Vector<int> int_vec;
int_vec.push_back(3);
int_vec.push_back(2);
std::cout << "-------- int vector ----------" << std::endl;
std::cout << "첫번째 원소 : " << int_vec[0] << std::endl;
std::cout << "두번째 원소 : " << int_vec[1] << std::endl;
Vector<std::string> str_vec;
str_vec.push_back("hello");
str_vec.push_back("world");
std::cout << "-------- std::string vector -------" << std::endl;
std::cout << "첫번째 원소 : " << str_vec[0] << std::endl;
std::cout << "두번째 원소 : " << str_vec[1] << std::endl;
}
template <class T>와 template <typename T>는 서로 동일한 의미를 갖는다.
❗typename 키워드를 사용하기를 권장한다.
template <typename T>
class Vector {
T* data;
int capacity;
int length;
}
Template의 인자에 값을 전달하기 위해서는 < > 키워드를 사용한다.
아래 코드는 T에 int라는 type이 전달된다.
Vector<int> int_vec;
따라서 아래 코드처럼 T가 int로 치환된다고 봐도 무방하다. 만약 Vector<std::string>의 경우 T→string으로 치환된다.
class template instantiation : 클래스 템플릿에 인자를 전달해서 실제 코드를 생성하는 것
Template Specialization(템플릿 특수화)
일부 타입(경우)에 대해서 따로 처리하는 것
template <typename A, typename B, typename C>
class test {};
A가 int고 C가 double 인 경우에 대해 따로 처리
template <typename B>
template <int, B, double> {};
함수의 템플릿(Function Template)
함수의 경우 클래스에서 사용된 < > 와 달리 변수의 타입을 보고 자동으로 인스턴스화(max<int> (a, b) 해준다.
#include <iostream>
#include <string>
template <typename T>
T max<T& a, T& b) {
return a > b ? a : b;
}
int main() {
int a = 1, b = 2;
std::cout << "Max (" << a << "," << b << ") ? : " << max(a, b) << std::endl;
std::string s = "hello", t = "world";
std::cout << "Max (" << s << "," << t << ") ? : " << max(s, t) << std::endl;
}
Function Object(Functor)
아래는 전체 코드다.
#include <iostream>
template <typename T>
class Vector {
T* data;
int capacity;
int length;
public :
typedef T value_type;
Vector(int n=1) : data(new T[n]), capacity(n), length(0) {}
void push_back(int s) {
if(capacity <= length) {
int* temp = new T[capacity*2];
for(int i=0; i< length; i++){
temp[i] = data[i];
}
delete[] data;
data = temp;
capacity *= 2;
}
data[length] = s;
length++;
}
T operator[](int i){ return data[i];}
void remove(int x){
for(int i=x+1; i< length; i++) {
data[i-1] = data[i];
}
length--;
}
int size() { return length; }
void swap(int i, int j) {
T temp = data[i];
data[i] = data[j];
data[j] = temp;
}
~Vector(){
if(data){
delete[] data;
}
}
};
template <typename Cont>
void bubble_sort(Cont& cont){
for(int i=0; i < cont.size(); i++){
for(int j=i+1; j<cont.size(); j++){
if (cont[i] > cont[j]){
cont.swap(i, j);
}
}
}
}
template <typename Cont, typename Comp>
void bubble_sort(Cont& cont, Comp& comp){
for (int i=0; i < cont.size(); i++){
for (int j=i+1; j<cont.size(); j++){
if(!comp(cont[i], cont[j])){
cont.swap(i, j);
}
}
}
}
struct Comp1 {
bool operator()(int a, int b) { return a > b; }
};
struct Comp2 {
bool operator()(int a, int b) { return a < b;}
};
int main() {
Vector<int> int_vec;
int_vec.push_back(3);
int_vec.push_back(1);
int_vec.push_back(2);
int_vec.push_back(8);
int_vec.push_back(5);
int_vec.push_back(3);
std::cout << "정렬 이전 ---- " << std::endl;
for (int i = 0; i < int_vec.size(); i++) {
std::cout << int_vec[i] << " ";
}
Comp1 comp1;
bubble_sort(int_vec, comp1);
std::cout << std::endl << std::endl << "내림차순 정렬 이후 ---- " << std::endl;
for(int i=0; i < int_vec.size(); i++){
std::cout << int_vec[i] << " ";
}
std::cout << std::endl;
Comp2 comp2;
bubble_sort(int_vec, comp2);
std::cout << std::endl << "오름차순 정렬 이후 ----- " << std::endl;
for (int i =0; i< int_vec.size(); i++){
std::cout << int_vec[i] << " ";
}
std::cout << std::endl;
}
위 코드 중에서 아래부분을 보면 다음과 같은 부분이 있는데 이는 operator() 만 정의하고 있다.
이 처럼 함수는 아니지만 함수 인 척하는 객체를 함수 객체(Function Object) → Functor 이라고 한다.
template <typename Cont, typename Comp>
void bubble_sort(Cont& cont, Comp& comp) {
for (int i = 0; i < cont.size(); i++) {
for (int j = i + 1; j < cont.size(); j++) {
if (!comp(cont[i], cont[j])) { //이 부분!!
cont.swap(i, j);
}
}
}
}
struct Comp1 {
bool operator()(int a, int b) { return a > b; }
};
struct Comp2 {
bool operator()(int a, int b) { return a < b;}
};
Meta Programming
타입은 컴파일 타임에 정해져야 함으로 컴파일 타임에 연산이 완료된다. 이렇게 타입을 가지고 컴파일 타임에 생성되는 코드로 프로그래밍
C++의 경우 템플릿을 가지고 이러한 작업을 하기 때문에 Template Meta Programming(템플릿 메타프로그래밍) 이라고 한다.
Comment