원문은 https://modoocode.com/에 잘 정리되어 있다. 모든 내용의 출처는 이곳이다. 원문내용을 보고 내용을 내 방식에 정리한 것이며, 원문의 출처에 자세하게 있다.
템플릿
템플릿이란 사용자가 원하는 타입을 넣어주면 알아서 코드를 찍어내는것이다.
C++에서 템플릿은 아래와 같이 선언하고 사용할 수 있다.
여기서는 List 클래스에 대한 템플릿을 명시하고 있다. 이렇게 정의한 템플릿의 인자에 값을 전달하기 위해서는
List<int...> 변수이름
과 같이 <> 안에 알맞은 타입을 사용하면 된다. T에 <>안에 있는 값을 템플릿 클래스가 받는다. 그리고 클래스 탬플릿에 인자를 전달해서 실제 코드를 생성하는 것을 클래스 템플릿 인스턴스화라고 한다.
아래는 코드의 예이다.
템플릿은 템플릿 특수화를 통해 일부 경우에 대해 따로 처리할 수 있는 기능이 있다.
typename에 일부 경우를 따로 처리하기 위해서 class 이름<명시할 타입,...> 으로 처리할 수 있다.
함수 템플릿
함수 템플릿도 클래스템플릿처럼 사용하는 방법은 동일하다.
클래스 템플릿과 마찬가지로, 이 함수도 인스턴스화 되기전까지 컴파일 시에 아무런 코드로 변환되지 않는다.
템플릿의 인자로는 타입이 아닌 템플릿 인자나 디폴트 템플릿 인자를 사용하여 사용할 수 있다.
전체 소스코드는 아래와 같다. 코드와 주석을 포함하였다.
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
|
// T라는 타입의 객체를 보관하는 클래스를 만들어보자
// 사용자가 원하는 타입을 넣어주면 알아서 코드를 찍어내주는 것이 템플릿
#include<iostream>
#include<string>
#include<array>
#include<vector>
template <typename T>
//아래에 정의되는 클래스에 대해 템플릿을 정의하고, 템플릿 인자로 T 를 받게 되며,
//T 는 반드시 어떠한 타입의 이름임을 명시
class List {
T* data;
int w;
int len;
public:
typedef T val_type;
// 생성자 초기화
List(int n = 1) : data(new T[n]), w(n), len(0) {}
// 뒤에 추가
void push_back(T s) {
if (w <= len) {
T* temp = new T[w * 2];
for (int i = 0; i < len; i++) {
temp[i] = data[i];
}
delete[] data;
data = temp;
w = w * 2;
}
data[len] = s;
len++;
}
//임의의 원소 접슨
T operator[](int i) { return data[i]; }
// 원소 삭제
void remove(int x) {
for (int i = x+1; i < len; i++) {
data[i - 1] = data[i];
}
len--;
}
int size() { return len; }
~List() {
if (data) {
delete[] data;
}
}
void swap(int a, int b) {
T temp = data[a];
data[a] = data[b];
data[b] = temp;
}
};
template <typename T> //함수 템플리스
T max(T& a, T& b) {
return a > b ? a : b;
}
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 (cont[i] > cont[j]) {
//cont.swap(i, j);
//} 기존의 하나의 정렬에 대해서만 작성된 코드
if (!comp(cont[i],cont[j])) {
//함수는 아니지만 함수 인 척을 하는 객체를 함수 객체 (Function Object), Functor
cont.swap(i,j);
}// 비교하는 함수를 만들어서 그 결과를 리턴하도록 함,
//하지만 함수가 아니라 이는 객체이고 Comp 클래스에서 연산자 오버로딩으로 한것
//comp 는 함수가 아니라 객체 이고, Comp 클래스에서 () 연산자를 오버로딩
}
}
}
template <typename T>
void just_print(const T& a) {
for (int i = 0; i < a.size(); i++)
std::cout << a[i] << " ";
std::cout << std::endl;
}
struct Comp {
bool operator()(int a, int b) { return a > b; }
};
struct Comp2 {
bool operator()(int a, int b) { return a < b; }
};
//클래스는 <>로 인스턴스화가 필요하지만 함수는 컴파일러가 알아서 해준다.
template <typename T>
struct info {
bool operator()(const T& a, const T& b) { return a < b; }
};
//디폴트 템플릿 인자
template <typename T, typename Comp = info<T>>
T Min(T a, T b) {
Comp comp; // Comp를 보면 디폴트 타입인 info를 받는다을 받는다.
if (comp(a, b)) return a;
else return b;
}
int main() {
// int 를 보관하는 벡터를 만든다.
List<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;
List<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;
List<int> int_vec2;
int_vec2.push_back(3);
int_vec2.push_back(1);
int_vec2.push_back(2);
int_vec2.push_back(8);
int_vec2.push_back(5);
int_vec2.push_back(3);
Comp comp1; // 오름을 하기위한 객체 생성
Comp2 comp2; // 객체 생성 내림
std::cout << "------- 정렬 이전 --------- " << std::endl;
for (int i = 0; i < int_vec2.size(); i++) {
std::cout << int_vec2[i] << " ";
}
std::cout << std::endl << "---------- 정렬 이후 --------- " << std::endl;
bubble_sort(int_vec2, comp1);
//함수를 호출한다면 컴파일러는 인자로 전달된 객체의 타입을 보고 알아서 인스턴스화 한 뒤에 컴파일함
//여기서는 List<int> 이므로 Cont = List<int>, 타입이 정의가 안되면 컴파일 에러임
for (int i = 0; i < int_vec2.size(); i++) {
std::cout << int_vec2[i] << " ";
}
std::cout << std::endl << "---------역정렬--------" << std::endl;
bubble_sort(int_vec2, comp2);
for (int i = 0; i < int_vec2.size(); i++) {
std::cout << int_vec2[i] << " ";
}
std::cout << std::endl;
//여기서 오름이나 내림 2가지를 함께 하는 방법? 연산자 오버로딩이 있지만 여기서는
//비교를 통한 특정 함수를 통해 만들어보자
std::array<int, 2> arr3 = { 1,2 };
std::vector<int> v = { 3,4,5,6 };
just_print(arr3);
just_print(v);
std::cout << "=========Default Templet===============" << std::endl;
// = 디폴트 와 같이 적용 가능 templete <typename T, int a> 타입도 가능
int a = 1, b = 3;
std::cout << "Min " << a << " , " << b << " :: " << Min(a, b) << std::endl;
std::string s1 = "abc", s2 = "def";
std::cout << "Min " << s1 << " , " << s2 << " :: " << Min(s1, s2)<< std::endl;
}
|
cs |
'C , C++, C#' 카테고리의 다른 글
[C/C++] define으로 플랫폼 체크 (0) | 2022.01.13 |
---|---|
[Cmake] Googletest setting Windows (0) | 2022.01.05 |
[C#] WinForm을 이용한 클래스 (0) | 2020.03.25 |
[C#] WinForm을 이용한 계산기 (0) | 2020.03.23 |
[C/C++] mutex 응용과 condition_value (0) | 2020.03.01 |