사용자가 원하는 타입을 넣어주면 해당 타입의 코드를 찍어내준다.
// 템플릿 첫 활용
#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;
}
위 코드의 클래스 부분을 보게되면 클래스에 대해 템플릿을 정의한 것을 볼 수 있음
T
: 템플릿 인자(어떠한 타입의 이름임)template <typename T>
Class Vector
가 오니 Vector
클래스에 대한 템플릿을 명시class Vector {
T* data;
int capacity;
// ...
템플릿으로 정의된 클래스를 사용
<>
안에 전달하려는 타입을 적으면 됨Vector<int> int_vec;
class Vector {
int* data;
int capacity;
int length;
public:
// 어떤 타입을 보관하는지
typedef T value_type;
// 생성자
Vector(int n = 1) : data(new int[n]), capacity(n), length(0) {}
// 맨 뒤에 새로운 원소를 추가한다.
void push_back(int s) {
if (capacity <= length) {
int* temp = new int[capacity * 2];
for (int i = 0; i < length; i++) {
temp[i] = data[i];
}
delete[] data;
data = temp;
capacity *= 2;
}
data[length] = s;
length++;
}
// 임의의 위치의 원소에 접근한다.
int 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;
}
}
};
이렇게 클래스 템플릿에 인자를 전달해서 실제 코드를 생성하는 것을 클래스 템플릿 인스턴스화(class template instantiation)라고 함
이와 같이 일부 경우에 대해서 따로 처리하는 것을 템플릿 특수화 라고 한다.
template <typename A, typename B, typename C>
class test{};
A가 int고 C가 double일 때 따로 처리하는 방법
template <typename B>
class test<int, B, double>{};
다음과 같이 특수화 해주면 됨
template <>
class Vector<bool> {
... // 원하는 코드
}
Vector을 구현하기 위해 int 배열을 이용한다. 1개의 int는 4byte이므로, 32개의 bool 데이터들을 한데 묶어서 저장 가능하다. 이를 통해 원래 방식대로라면 bool이 1바이트로 저장되지만, 이렇게 하면 bool을 1비트로 정확히 표현 가능해진다.
Vector(int n = 1)
: data(new unsigned int[n / 32 + 1]), capacity(n / 32 + 1), length(0) {
for (int i = 0; i < capacity; i++) {
data[i] = 0;
}
}
template <typename T>
T max(T& a, T& b) {
return a > b ? a : b;
}
Cont
: 클래스를 템플릿 인자로 받음Comp
: 함수또한 객체를 받음comp
라는 객체가 cont[i]
과 cont[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);
}
}
}
}
#include <iostream>
template <typename T, int num>
T add_num(T t) {
return t + num;
}
int main() {
int x = 3;
std::cout << "x : " << add_num<int, 5>(x) << std::endl;
}