가변인자를 받는 함수의 경우 Parameter Pack을 통해 args를 사용할 수 있다.
인자가 몇 개 있는지 알고 싶으면 sizeof... 를 사용하면 됨
sizeof...에는 타입도 넣을 수 있다.
sizeof...(Types);
sizeof...(args);
Parameter Pack을 통해 다른 함수로 인자를 보낼 경우
goo(args) 이렇게 보낼 순 없으나 goo(args...)로 풀 수 있음
goo(args...) == goo(1, 3.4, "AAA")
Pack 심화
template<typename ... Types>
void foo(Types ... args)
{
int x[] = { (++args)...}; // pack expansion
for (auto n : x)
std::cout << n << std::endl;
}
int main()
{
foo(1, 2, 3);
}
int x[] = (++args)...; 는 ... 앞에 걍 파라미터 팩이 오는 게 아니라 파리미터팩을 사용한 패턴이 옴
int x[] = { hoo(args)... }; 이것은 함수를 이용한 패턴인데, ...을 함수 인자 내부에 쓰는 게 아닌 밖에 쓴다.
함수 자체를 패턴이라고 생각하는 게 편할듯
int print(int a) {
std::cout << a << std::endl;
return 0;
}
template<typename ... T>
void test(T ... args)
{
print(args)...;
// 팩을 확장할땐 함수 인자에서 하거나, 배열 만들때 확장이 됨 {...}
// Pack Extension은 아무데서나 할 수 있는게 아님
int x[] = {0, print(args)...};
// 인자가 없는 경우 이렇게 사용이 가능하다.
int x[] = {0, (print(args), 0)... };
// print가 void를 리턴하는 경우 이렇게 사용하면 에러가 나지 않음
initializer_list<int> e = ~~
// 전체 수식의 결과는 콤마 뒤에 있는 값을 쓰겠다는 뜻
// 이니셜라이저리스트에서 받으면 아무것도 보내지 않아도 에러가 나지 않음
}
int main()
{
test(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
}
결과적으로 비교적 깔끔하지 않은데 C++17에서 지원하는 폴드 익스프레션을 통해 보완 가능함
Types에 대한 Pack Expansion
args 뿐만 아니라 Types도 Pack Expansion이 가능하다.
#include <iostream>
#include <algorithm>
#include <tuple>
template<typename ... Types>
void foo(Types ... args)
{
// ...의 위치를 잘 파악해야 함
std::pair<Types...> p1;
std::tuple<Types...> t1;
std::tuple<std::pair<Types...>> t2; // tuple<pair<int, double>> 이므로 문제 없음
std::tuple<std::pair<Types>...> t3; // tuple<pair<int>, pair<double>> pair가 인자 2개를 받아야 하므로 error!
std::tuple<std::pair<int, Types>...> t4; // tuple<pair<int, int>, pair<int, double>> 이상 없음!
std::pair<std::tuple<Types...>> p2; // pair<tuple<int, double>> 인자가 1개이므로 error!
std::pair<std::tuple<Types>...> p3; // pair<tuple<int>, tuple<double>> pair의 인자가 2개이므로 문제 없음
}
int main()
{
foo(1, 3.4);
}
...의 위치가 괄호 안이냐 밖이냐에 따라 어떻게 Expansion할 것인지 의미가 달라짐
// Types == (int, double)
// std::pair<Types...> 처럼 안에서 ...을 적어주면 안에서 Expansion
std::tuple<std::pair<Types...>> -> std::tuple<std::pair<int, double>>
// std::pair<Types>... 처럼 밖에서 ...을 적어주면 Types의 요소를 하나씩 ... 안에 담아서 Expansion
std::tuple<std::pair<Types>...> -> std::tuple<std::pair<int>, std::pair<double>>
args의 각 요소를 꺼내는 방법
#include <iostream>
#include <algorithm>
#include <tuple>
template<typename ... Types>
void foo(Types ... args)
{
//각 요소를 꺼내는 방법
//int x[] = { args... }; //그러나 다른 타입이 있을 수 있으므로 이러면 안됨
//tuple 사용법
std::tuple<Types...> tp(args...);
std::cout << std::get<0>(tp) << std::endl;
std::cout << std::get<1>(tp) << std::endl;
std::cout << std::get<2>(tp) << std::endl;
}
int main()
{
foo(1, 3.4, "AAA");
}
댓글