BLOG main image
분류 전체보기 (222)
Reversing (13)
Pwnable (4)
Linux Kernel (3)
Crypto (2)
Wargames (66)
Programming (18)
Write Up (32)
Project (22)
Web (2)
My Life (52)
Memo (3)
etc (2)
발표자료 (1)
36,063 Visitors up to today!
Today 12 hit, Yesterday 30 hit
daisy rss
tistory 티스토리 가입하기!
2017.08.29 14:16


두 값을 더하는 add연산을 하는 함수를 만들어야 한다는 상황을 가정해보자

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
#include <iostream>
 
/*
int add(int a, int b) {
    return a + b;
}
double add(double a, double b) {
    return a + b;
}
std::string add(std::string a, std::string b) {
    return a + b;
}
*/
 
template <typename T>
T add(T a, T b) {
    return a + b;
}
 
// 특수화 (Specialization)
template <typename T>
int add(int* a, int* b) {
    return *+ *b;
}
 
int main(void) {
    int a = 10, b = 20;
    double c = 10.4, d = 20.4;
    std::string s = "Hello", t = "World";
    int* pA = &a;
    int* pB = &b;
 
    int sum = add(a, b);
    double sum2 = add(c, d);
    std::string sum3 = add(s, t);
    int pSum = add<int*>(pA, pB);    // using specialization template
 
    std::cout << pSum << std::endl;
}
cs

템플릿이 없었다면 주석처럼 각 타입마다 모두 add함수를 만들어서 사용해야 할 것이다.
그런데 템플릿을 사용하면 이렇게 타입에 대해서 T로 표시하고 어찌어찌 해서 들어오는 타입대로 더할 수 있게 된다.
특정 자료형만 따로 정의할 일이 있으면 위에처럼 특수화를 해서 정의하면 된다.

그럼 int와 double은 어떻게 더해야 하는가? 
int + double은 double이지만 어떤 값이 double인지 알아내기는 쉽지 않다.
여러가지 대처 방법이 있을 수 있는데 가장 무난하고 권장되는 방법은

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
 
template <typename T1, typename T2>
auto add(T1 a, T2 b) -> decltype(a + b) {
    return a + b;
}
 
int main(void) {
    auto e = 10.4f;
    decltype(e) f = 24.5f;    // e의 타입으로 정의
 
    int a = 10;
    double b = 20.4;
 
    std::cout << add(a, b) << std::endl;
    std::cout << add(b, a) << std::endl;
}
cs

이렇게 auto로 반환하되 auto의 타입을 decltype을 이용해서 a + b의 타입으로 맞춰주면 된다.

다음은 가변인자에 대한 가변 템플릿이다.

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
#include <iostream>
 
/*
int sum(int a, int b) {
    return a + b;
}
int sum(int a, int b, int c) {
    return a + b + c;
}
int sum(int a, int b, int c, int d) {
    return a + b + c + d;
}
int sum(int a, int b, int c, int d, int e) {
    return a + b + c + d + e;
}
// ...
*/
 
// C++11 : Variadic Template (가변 템플릿)
template <typename T, typename... Args>
T sum(T a, Args... args) {
    return a + sum(args...);
}
 
template <typename T>
T sum(T a) {
    return a;
}
 
int main(void) {
    int a = 1, b = 2, c = 3;
 
    std::cout << sum(a, b) << std::endl;
    std::cout << sum(a, b, c) << std::endl;
}
cs

가변 템플릿이 없었다면 주석에 있는 것처럼 모든 인자의 개수에 맞춰서 다 정의를 미리 해주어야한다.
그런데 가변 템플릿을 사용하면 그럴 필요가 없다.

가변 템플릿은 재귀적인 형태로 이루어지며 가변 인수를 받는 템플릿 함수와 재귀적으로 돌다가 인자가 하나만 남았을 때 처리하는 함수 총 두개가 필요하다.

가변 템플릿은 위에 처럼 쓰면 댄다.
그리고 저 가변 템플릿은 코드상에서는 재귀지만 컴파일 타임때 재귀는 모두 풀리고 그냥 함수로 풀려서 실제 컴파일 하면 재귀로 실행되지 않는다.
그래서 재귀함수의 오버헤드가 발생하지 않는다.

그럼 가변 템플릿과 이것 저것을 응용해서 

1
2
3
4
5
6
#include <iostream>
 
int main(void) {
    std::cout << 'a' << 3 << "String" << 3.14 << std::endl;
    PrintList('a'3"String"3.14);
}
cs

4번 라인과 5번 라인이 똑같이 나오도록 PrintList함수를 만들어보자.

물론 인자 개수와 타입은 각각 바뀔 수 있다.

알아서 만들자

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

C++에서 문자열 EOF까지 입력받고 출력하기  (0) 2018.04.24
c++ 템플릿 공부  (0) 2017.08.29
Lvalue와 Rvalue  (0) 2017.05.20
Name
Password
Homepage
Secret
prev"" #1 #2 #3 next