가변 길이 템플릿

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
#include <iostream>
 
template <typename T>
void print(T arg) {
 
    std::cout << arg << std::endl;
 
}
 
template <typename T, typename...Types>
void print(T arg, Types... args) {
 
    std::cout << arg << ", ";
 
    print(args...);
 
}
 
int main() {
 
    print(13.1"abc");
 
    print(1234567);
 
}
cs

 

typename <typename T, typename... Types>

 -> 템플릿 파라미터 팩, 0개 이상의 템플릿 인자들을 나타낸다. (타입 앞에 ...)

 

void print(T arg, Types... args) {

 -> 함수 파라미터 팩, 0개 이상의 함수 인자를 나타낸다. (타입 뒤에 ...)

 

파라미터 팩은 추론된 인자를 제외한 나머지 인자들을 나타낸다.

예를 들어 위의 코드 중 print(1, 3.1, "abc")를 호출할 경우 컴파일러는 두 개의 print() 중

어느것을 선택할지 정해야 한다. 첫 번쨰 print()는 1개의 인자만을 받으므로 제외되고 두 번째 print()가 

선택된다.

 

만약 인자의 수가 같거나 0개일 경우 파라미터 팩이 없는 함수가 우선순위를 가진다. 

 

c++컴파일러는 함수 컴파일 시 자신의 앞에 정의되어 있는 함수들 밖에 보지 못하므로 특정 함수의 존재 자체를 

모를 수도 있다. 따라서 템플릿 함수 작성 시 순서에 유의해야 한다. 

 

 

가변 길이 템플릿 예제 - 임의의 개수의 문자열을 합치는 함수 

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
#include <iostream>
#include <cstring>
#include <string>
 
 
// 임의의 개수의 문자열을 받아서 각각의 길이를 더한 것들을 리턴
// const char* 으로 받는 경우  
size_t GetStringSize(const char* s) {
 
    return strlen(s);
}
 
// std::string 으로 받는 경우
size_t GetStringSize(const std::string& s) {
 
    return s.size();
}
 
template <typename String, typename... Strings>
size_t GetStringSize(const String& s, Strings...strs) {
 
    return GetStringSize(s) + GetStringSize(strs...);
}
 
// 아무 인자도 없을때까지 반복하므로 재귀호출을 끝내기 위해 아무 값도 전달해주지 않음
void AppendToString(std::string* concat_str) {
 
    return;
}
 
// 첫 번째 인자로는 합쳐진 문자열을 보관할 문자열을 계속 전달
// 그 다음 인자들로는 합쳐질 문자열들을 계속 전달
template <typename String, typename...Strings>
void AppendToString(std::string* concat_str, const String& s, Strings... strs) {
 
    concat_str->append(s);

    AppendToString(concat_str, strs...);
}
 
template <typename String, typename... Strings>
std::string StrCat(const String& s, Strings...strs) {
 
    // 합쳐질 문자열의 총 길이를 구한다
    size_t total_size = GetStringSize(s, strs...);            
 
    // 합쳐진 문자열을 보관하는 변수
    std::string concat_str;
 
    // reserve() -> 메모리 저장할 공간을 예약 
    //              메모리가 필요없이 재할당 되는 것을 막아줌 
    //              어느정도의 메모리를 할당해 둠으로써 재할당 횟수를 최소화 시켜줌 
    // reserve()를 이용해 필요한 만큼 미리 공간을 할당
    concat_str.reserve(total_size);
 
    // 템플릿으로 받은 문자열을 concat_str 변수에 저장
    concat_str = s;
 
    // 템플릿으로 받은 나머지 인자들을 AppendToString()을 통해 
    // 붙여줌
    AppendToString(&concat_str, strs...);
 
    return concat_str;
}
 
int main() {
    std::cout << StrCat(std::string("this"), " ""is"" ", std::string("a"),
        " ", std::string("sentence")) << std::endl;
}
cs

 

sizeof 

 - 템플릿 전체 인자의 개수를 리턴

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
#include<iostream>
 
int sum_all() {
 
    return 0;
}
 
// 전달된 인자들의 합을 리턴하는 함수
template <typename...Ints>
int sum_all(int num, Ints... nums) {
 
    return num + sum_all(nums...);
 
}
 
// 전달된 전체 인자 개수로 합을 나눠주는 함수
template <typename...Ints>
double average(Ints...nums) {
 
    // static_cast -> 형변환 (int형 -> double형 형변환)
    // sizeof...() -> sizeof... 에 파라미터 팩을 전달하면 
    // nums에 해당하는 실제 인자의 개수를 리턴해준다. 
    return static_cast<double>(sum_all(nums...)) / sizeof...(nums);
 
}
 
int main() {
 
    std::cout << average(142310<< std::endl;
 
}
cs

sizeof...에 파라미터 팩 (nums)를 전달해주면 nums에 해당하는 실제 인자의 개수를 리턴해준다.

 

 

Fold Expression

 - 위의 예제 코드들 처럼 가변 길이 템플릿은 재귀 함수 형태로 구성해야 하기 때문에 반드시 재귀 호출 종료를

   위한 함수를 따로 만들어야 했다. 하지만 Fold형식을 사용하면 이를 훨씬 간단하게 표현할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>
 
template <typename...Ints>
int sum_all(Ints... nums) {
 
    return (... + nums);
}
 
int main() {
 
    std::cout << sum_all(142310<< std::endl;
}
cs

위의 예제 코드 중 return (... + nums); 부분이 Fold 형식으로 이 코드는 컴파일러에서 

return ((((1+4) + 2) + 3) + 10); 과 같이 해석된다. 이와 같은 형태를 단항 좌측(Unary left fold) 이라고 한다. 

 

 

https://modoocode.com/290 참고

'c++' 카테고리의 다른 글

클래스 (Class)와 구조체 (Struct)의 차이  (0) 2020.08.28
함수 템플릿  (0) 2020.08.27
템플릿 (Template)  (0) 2020.08.27
오버라이딩, 가상함수  (0) 2020.08.20
String class  (0) 2020.08.18
TAGS.

Comments