두 값을 더하는 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 *a + *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 |
---|---|
Lvalue와 Rvalue (0) | 2017.05.20 |