+ 이 글은 작성자가 직접 공부하고 복습하며 작성한 글입니다. 만약 직접 작성하지 않았다면, 꼭 출처를 밝히겠습니다!

 + 이 글은 개인적인 공부를 바탕으로 작성되었기에, 틀린 부분이 있을 수 있으며, 틀린 부분이 있다면 알려주시면 감사하겠습니다!

 + 이 글을 다른 곳으로 가져가신다면, 꼭 출처를 남겨주세요~

 + '참고사이트'는 공부하기 위해 참고한 사이트들을 모아 둔 것입니다.

 + 혹시라도 문제가 된다면 바로 조취를 취할테니, 말해주시면 감사하겠습니다!


 코딩을 하다보면, 라이브러리로 구현된 함수 중, Parameter의 갯수에 상관없이 사용할 수 있는 함수들을 많이 보게됩니다. 대표적으로 printf(...)와 같은 출력문들이 그러한데요, 이러한 함수들은 구현될 때, 모든 경우에 대해서 overloading하는 것이 아닙니다. "Parameter pack"을 이용하여, 함수를 실행시키는 것이죠!!


[Parameter Pack]

 + 이름 그대로 인자들의 묶음을 나타냅니다.


 + 인자들을 묶어서 하나의 인자로 취급하니, 여러 인자를 한 번에 사용할 수 있습니다.


 + Parameter pack은 말 그대로 인자들의 묶음으로, 따로 자르거나 내부를 꺼내어 사용할 수 없습니다. 그냥 그 자체로 사용됩니다.


[Syntax]

'

type...Args

typename | class...Args

template<parameter-list> typename|class...Args

Args...args

'

 + 예시

'

template<class ... Types> struct Tuple {};
Tuple<> t0;           // Types contains no arguments
Tuple<int> t1;        // Types contains one argument: int
Tuple<int, float> t2; // Types contains two arguments: int and float
Tuple<0> error;       // error: 0 is not a type


template<class ... Types> void f(Types ... args);
f();       // OK: args contains no arguments
f(1);      // OK: args contains one argument: int
f(2, 1.0); // OK: args contains two arguments: int and double

'


 + Parameter pack을 사용할 때, 해당 pack 변수는 인자가 없는 상황부터 인지하게 됩니다.

`

template<typename... Args>

void temp(int value, Args... args){...} 

// Can Use : temp(1);, temp(1,2);, temp(1,2,"asdf");

// Can't Use : temp();

`


 + 일단 간단히 사용되는건 이렇고, 좀 더 자세한 것은 날잡아서 더 공부해야할 것 같습니다.


 + printf(...)와 같은 출력문에서 많이 사용된다고 했었는데요, 예시로 한 번 만들어 보겠습니다!

'

#include <iostream>
 
void tprintf(const char* format) // base function
{
    std::cout << format;
}
 
template<typename T, typename... Targs>
void tprintf(const char* format, T value, Targs... Fargs) // recursive variadic function
{
    for ( ; *format != '\0'; format++ ) {
        if ( *format == '%' ) {
           std::cout << value;
           tprintf(format+1, Fargs...); // recursive call
           return;
        }
        std::cout << *format;
    }
}
 
int main()
{
    tprintf("% world% %\n","Hello",'!',123);
    return 0;
}


output : Hello world! 123

'

1) format변수로 나타낼 문장의 위치를 잡습니다. 그리고 value로 다음으로 출력될 변수를 지정하고, 마지막 parameter pack으로 출력될 변수들을 저장하면됩니다.


2) 한 칸씩 전진하면서 구분자를 찾고, 해당 구분자가 나오면 value를 출력해줍니다.


3) value를 출력하고나서는 다음 출력될 변수를 앞으로 당기기 위해 함수를 recursive합니다.


4) 마지막으로, value가 없는 상황을 대비해서 format만 남은 함수를 overloading해줍니다.

   - Overloading을 해주지 않으면, 인자가 하나밖에 없는 상황에선 맞지않는 함수로 인식해 compile error가 발생합니다.


[resursive]

 + 왜 recursive를 해주는지 의아하실 수 있습니다. 그 점을 설명하자면, parameter pack은 그 내부를 하나하나 사용할 수 있는 변수가 아닌, 인수의 집합, 그 자체입니다. 따로 나눌수도 없이, 그냥 어떤 type의 변수들을 가지고 있다는 덩어리죠. 그렇기에 자동적으로 구분해서 사용할 수 있게 만들어야합니다. 그러한 방법으로 recursive를 사용한 것이죠. 위의 함수를 보게되면, recursive를 해주는 부분에 value가 없고 바로 parameter pack이 있습니다. 저렇게 하면 자동으로 parameter pack의 첫 번째 변수가 value로 가게 되는 것이죠. 그림으로 보여드리면

tprintf(1,2,3,4); //format : 1, value : 2, Targs : 3,4

그리고 다음 recursive를 하게 될 때는,

tprintf(1`,3,4); // format : 1`, value : 3, Targs:4

가 됩니다.

즉, 자동으로 parameter pack의 인자들을 하나하나 잘라서 사용하게 되는 것이죠. 이렇기에 recursive를 사용한 것입니다.



*** 참고해야하는 점

 - parameter pack은 따로 내부를 자르거나 꺼내서 사용할 수 없습니다. 그 자체가 변수들을 가지고 있는 덩어리로 취급됩니다.




Copyright © -강정이좋아- 무단 전재 및 재배포는 하지 말아주세요.

+ Recent posts