본문 바로가기

진리는어디에/C++

[C++11] Variadic template(Parameter pack)

Variadic template

C++에서는 Parameter pack이라고 불리며, 수가 정해지지 않은 N개의 인자를 사용 할 수 있는 기능으로써 D언어와 C++ 11에서 지원하고 있다

en.cppreference.com/w/cpp/language/parameter_pack

 

Parameter pack(since C++11) - cppreference.com

A template parameter pack is a template parameter that accepts zero or more template arguments (non-types, types, or templates). A function parameter pack is a function parameter that accepts zero or more function arguments. A template with at least one pa

en.cppreference.com

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;
}

부록 1. 참조

유익한 글이었다면 공감(❤) 버튼 꾹!! 추가 문의 사항은 댓글로!!