Variadic template
C++에서는 Parameter pack이라고 불리며, 수가 정해지지 않은 N개의 인자를 사용 할 수 있는 기능으로써 D언어와 C++ 11에서 지원하고 있다
en.cppreference.com/w/cpp/language/parameter_pack
C++ 11 이전 버젼의 템플릿에서는 지정된 갯수만큼의 인자만을 받을 수 있었으나 C++11에서 부터는 임의의 갯수를 받을 수 있도록 변경 되었다. 기본적인 문법은 아래와 같다 :
template<typename... Values> class tuple;
위의 템플릿 클래스 tuple은 어떠한 타입이든 몇개든 상관 없이 템플릿 인자 생성이 가능 하다. 예를 들어서 위 클래스의 인스턴스로 아래와 같은 것이 가능하다 :
tuple<int, std::vector<int>, std::map<std::string, std::vector<int>>> some_instance_name;
물론 0개의 템플릿 인자로도 인스턴스 생성이 가능하고 tuple<>some_instance_name 과 같은 코드도 정상 동작한다. 만일 최소한 하나의 인자는 받아야 한다라고 강제하고 싶다면 아래와 같은 코드도 가능 하다 :
template<typename First, typename... Rest> class tuple;
위 코드에서는 tuple<> some_instance_name 과 같은 코드는 컴파일 에러를 발생 시킨다.
Variadic template은 템플릿 특화(Template specialize)와 결합해서 사용하면 가변인자를 이용한 함수(va_list) 와 같은 기능을 하지만 %c, %d와 같은 귀찮은 예약 인자와 순서를 맞춰야만 하는 귀찮음을 제거 할 수 있는 강력한 도구가 된다.
아래 코드는 임의의 타입으로 구성된 임의의 갯수의 인자를 받아 결합하여 문자열로 리턴 하는 함수를 variadic template을 이용하여 구현 한것이다 :
#include <string>
#include <sstream>
#include <iostream>
template <class T>
void Concat(std::stringstream& stream, const T& t) // 종료 템플릿 함수
{
stream << t;
}
template <class T, class... ARGS>
void Concat(std::stringstream& stream, const T& t, ARGS&&... args) // 재귀 템플릿 함수
{
stream << t;
Concat(stream, args...);
}
template <class... ARGS>
std::string Concat(ARGS... args) // 유저 호출 함수
{
std::stringstream stream;
Concat(stream, args...); // 템플릿 특화로 인해 재귀 템플릿 함수가 호출 된다.
return stream.str();
}
int main()
{
int n100 = 100;
int n200 = 200;
float f100 = 100.0f;
float f200 = 200.0f;
std::string str = "string out";
std::cout << Concat("string ", n100, " ", str, " ", n200, " ", f100, " ", f200 ) << std::endl;
printf("string %d %s %d %f %f", n100, str.c_str(), n200, f100, f200);
return 0;
}