본문 바로가기

C++

C++11 가변인자 템플릿 (Variadic template)

나는 생산성을 높여주는 템플릿을 좋아하는편이다.

 

그중 최신에 알게된 가변인자 템플릿을 무척 편리하게 써먹은 적이 있다.

 

 

가변인자 템플릿(Variadic template)

 

printf에 사용해 왔던 가변 인자 함수(Variadic function)와 조금 닮은면이 있다. (va_list)

가변인자템플릿의 template...파라미터팩(parameta pack) 이라고 불린다.

 

 

예제코드

#include "stdio.h"
#include "tchar.h"

typedef unsigned char BYTE;

class cPacket
{
public:
    enum { BUFF_MAX = 1024 };

    //  기본 생성자
    cPacket()
        : m_pCur(m_byBuff)
        , m_pEnd(m_byBuff + BUFF_MAX)
    {
        memset(m_byBuff, 0, BUFF_MAX);
        printf("init\n");
    }

    //  소멸자
    ~cPacket() {}; 

    //  템플릿 가변인자 생성자
    template <typename... pack> // 파라미터팩(parameta pack)
    cPacket(pack... args) : cPacket()
    {
        //  sizeof...(args) 로 가변인자의 사이즈도 알수있다.
        printf("parameta pack size = %llu \n", sizeof...(args)); 

        // 생성자를 재귀호출할순 없으니, 파라미터팩을 전달인자로 가지는 재귀함수를 호출하자.
        push(args...);
        end_push();
    } 
    
    // 이 함수에 인자가 하나남을때까지 재귀호출된다.
    template <typename T, typename... pack>
    void push(T Data, pack... args)
    {
        push(Data);
        push(args...);  // 재귀호출
    }

    //  실제 처리되는 함수
    template <typename T>
    void push(T Data) 
    { 
        const int nSize = sizeof(T); 
        if (m_pCur + nSize > m_pEnd) 
        { 
            printf("overflow\n"); 
            return; 
        } 
        memcpy(m_pCur, &Data, nSize); 
        m_pCur += nSize; 

        //  디버깅용 로그 1
        printf("push:%d\n", Data); 
    }  

    //  버전에따라 파라미터가 빈 함수도 생성해야할때도 있다. 
    //void push(void) {}


    void end_push(void)
    {
        m_pEnd = m_pCur;
        m_pCur = m_byBuff;
        
        //  디버깅용 로그 2
        printf("push end\n");
    }

    template <typename T>
    void pop(T& Data)
    {
        const int nSize = sizeof(T);
        if (m_pCur + nSize > m_pEnd)
        {
            printf("overflow\n");
            return;
        }
        memcpy(&Data, m_pCur, nSize);
        m_pCur += nSize;
        printf("pop:%d\n", Data);
    }

private:
    BYTE    m_byBuff[BUFF_MAX];
    BYTE*   m_pCur;
    BYTE*   m_pEnd;
};



int main()
{
    //  생성자로 int형 데이터 8개 입력
    cPacket pk(0, 1, 2, 3, 4, 5, 6, 7);

    int nFoo;
    //  제대로 들어갔는지 확인해보자.

    for (int i = 0; i < 9; ++i)
        pk.pop(nFoo);
}

 

실행결과

init
parameta pack size = 8
push:0
push:1
push:2
push:3
push:4
push:5
push:6
push:7
push end
pop:0
pop:1
pop:2
pop:3
pop:4
pop:5
pop:6
pop:7
overflow

일부러 pop를 한번 더 실행해서 overflow를 확인해보았다.

 

이런식으로 패킷 함수를 만들어놓으면 앞으로가 편안할것이다. 흐믓

'C++' 카테고리의 다른 글

C++11 람다 함수 (Lambda Function)  (0) 2020.04.26
C++11 stl에 추가된 emplace(insert), emplace_back(push_back)  (0) 2020.04.17
C++11 enum class  (1) 2020.04.12
유니코드 문자열 처리  (0) 2020.04.12
printf문의 서식지정자  (0) 2020.04.12