프로그래밍/C/C++

c++ 템플릿 가변인자 Variadic template

nanze 2021. 12. 29. 12:10
반응형

항상 자주 마주치지만 익숙하지 않은 템플릿에 대해서 정리해보자. 템플릿에서 인자로 받을 수 있는 것은 무엇이 있을까?

일단 변수는 되지 못한다. 그리고 실수 값도 사용이 불가하다. 그렇다 템플릿 인자로 가능한 것은 정수형 상수이거나 타입일 경우에만 가능하다. 

다음의 코드를 보자. 

template <typename T=char, int SIZE = 3>
class CTemplateTest
{
    T tName[SIZE];
};

int main()
{
    CTemplateTest<short, 20> test1;
    CTemplateTest<short, 1.2> test2;  // 정수값만 가능.
    CTemplateTest test3; //템플릿 인자를 명시해야 함
    int value = 10;
    CTemplateTest<short, value> test4; //변수 불가능. 
    CTemplateTest<> test5;
    
    return 0;
}

위 코드는 템플릿 인자에 대해서 실수 값과 변수는 사용이 불가능하다는 것을 보여주고 있다.

다음은 조금더 어려운 가변인자 템플릿에 대해서 알아보자. 가변인자 템플릿은 C++ 11 부터 지원되는 것으로 템플릿 인자안에는 여러 개의 값이 들어있다. 자 코드부터.

#include <iotream>

template<typename... Types>
class VariadicTemplate
{

};

template<typename... Types>
void variadicFunction(Types... args)
{

}

int _tmain()
{
    VariadicTemplate<int> test1;
    VariadicTemplate<int, int> test2;
    VariadicTemplate<int, int, int> test3;
    
    variadicFunction();
    variadicFunction(1);
    variadicFunction(1,2);
    variadicFunction(1,2,"1");
    return 0;
}

템플릿의 가변인자를 이용하여 전달받은 집합을 parameter pack 이라고 하며 sizeof... 함수를 이용하여 인자에 포함된 개수를 아는 것이 가능하다. 또한 템플릿 가변인자를 받은 후 다시 그대로 가변인자를 전달하는 방법이 있는데 이것을 pack expansion 이라고 한다. 

 

pack expansion 은 parameter pack 에 '...' 을 붙이면 해당 패턴이 ',' (쉼표) 구분자로 요소들이 나뉘어지는 방식이다. 

예를들어 Types... args 에 1, 2, 3, 4, 5 가 들어올 경우 다음 표현식과 의미이다. 

args... = 1, 2, 3, 4, 5
(--args)... = 0, 1, 2, 3, 4
function(args...) = function(1, 2, 3, 4, 5);
func(function(args)...) = func(function(1), function(2), function(3), function(4), function(5));

pack expansion 은 사용가능 한 곳이 정해져있는데 그것은 바로 함수 호출 인자로 사용될 경우와 배열 등의 초기화 표현식으로 사용될 경우이다.

코드를 보자.~!

#include <iostream>

using namespace std;

int addAll()
{
    return0;
}

template<typename... Args>
int addAll( int num, Args... numbers)
{
    return num + addAll(numbers...);
}

template <typenmae... Args>
double getAverage(Args... numbers)
{
    return static_cast<double>( addAll(numbers...) / sizeof...(numbers) );
}

int _tmain()
{
    double avg = getAverage(23, 4, 87, 34, 22);
    wcout << L"the average is " << avg << endl;
    return 0;
}

위 코드는 가변 템프릿과 재귀 방식을 이용하여 들어온 인자들의 평균 값을 구하는 함수이다. 재귀함수 호출 시 중요한 점은 모다 ? 끝부분이다. 마지막 부분에서 반환되서 올라올 수 있도록 해주어야 한다. 여기선 그 역할을 인자가 0개 일 때 호출되는 addAll() 함수가 그 역할을 한다. 

C++ 17에서는 이부분도 필요없는 Fold 방식을 지원한다고 하는데 그것은 나중에 알아보자. 

반응형