1. 가변인자(Variable argument)

=> 변수의 개수가 변하는 인자

=> 함수나 템플릿의 파라미터로 원하는 만큼의 갯수를 넣을 수 있는 것

=> 마지막 멤버가 (...)인 선언

=> #include <cstdarg>를 사용(C는 stdarg.h)

=> 순서

    -> 1. 인수에 Access 전에 va_list 변수로 목록 표시 설정

    -> 2. va_arg 매크로를 통하여 인수에 엑세스

    -> 3. va_arg 매크로를 원하는 식에 사용하여 얻은 결과를 명시적 캐스팅

    -> 4. va_end로 인수처리 종료

#include<iostream>
#include<cstdarg>

using namespace std;

void Func(int args, ...)
{
    va_list v1;
    va_start(v1, args);
    
    for(int i = 0; i<args; ++i)
    {
    	if(i%2 == 0)
		int temp = va_arg(ap,int);
        else
        	int temp = va_arg(ap, double);
        cout << "args : " << args << " : " << temp << endl;
    }
    va_end(v1);
}
            

 

2. 가변인자 템플릿(Variadic template)

=> Typename T는 여러개의 타입을 말함

=> C++11부터 지원

#include<iostream>
using namespace std;

template<typename ... T> 
class A
{
};

template<typename ... T>
void Func_A(T ... args)
{
}

int main()
{
// Class Template
	A<> a;
    A<int> b;
    A<int, char> c;
    
// Function Template
    Func_A();
    Func_A(1);
    Func_A(1,"B");
    return 0;
}

=> Parameter Pack이 존재

    -> Parameter Pack : 가변인자 함수 템플릿의 인자 args의 파라미터 집합

    -> sizeof...(args)로 사이즈를 얻을 수 있음

    -> Pack Expansion : 함수호출 인자 혹은 list 초기화를 사용한 식에서만 사용 가능

 

3. Pack Expansion

=> 줄임표(...)를 통하여 하나 이상의 Parameter pack을 포함하는 표현식

template<class...T>
void func(T...a)
{
}; // T pack의 확장

template<class...U>
void func1(U...b)
{
	func(b...);
}; // U pack의 확장

=> 함수 호출 인자 또는 list초기화를 사용한 표현식에서 사용

    -> Expression list : 스위치 안에 pack expansion args 사용

#include <cstdio>
#include <cassert>

template<class...A> void func1(A...arg){
    assert(false);
}

void func1(int a1, int a2, int a3, int a4, int a5, int a6){
    printf("call with(%d,%d,%d,%d,%d,%d)\n",a1,a2,a3,a4,a5,a6);
}

template<class...A> int func(A...args){
    int size = sizeof...(A);
    switch(size){
        case 0: func1(99,99,99,99,99,99);
        break;
        case 1: func1(99,99,args...,99,99,99);
        break;
        case 2: func1(99,99,args...,99,99);
        break;
        case 3: func1(args...,99,99,99);
        break;
        case 4: func1(99,args...,99);
        break;
        case 5: func1(99,args...);
        break;
        case 6: func1(args...);
        break;
        default:
        func1(0,0,0,0,0,0);
    }
    return size;
}

int main(void){
    func();
    func(1);
    func(1,2);
    func(1,2,3);
    func(1,2,3,4);
    func(1,2,3,4,5);
    func(1,2,3,4,5,6);
    func(1,2,3,4,5,6,7);
    return 0;
}
//출처 : https://www.ibm.com/docs/en/zos/2.3.0?topic=only-variadic-templates-c11

    -> Initializer list : res의 initializer에서 Pack expansion args 사용

#include <iostream>
using namespace std;

void printarray(int arg[], int length){
    for(int n=0; n<length; n++){
        printf("%d ",arg[n]);
    }
    printf("\n");
}

template<class...A> void func(A...args){
    const int size = sizeof...(args) +5;
    printf("size %d\n", size);
    int res[sizeof...(args)+5]={99,98,args...,97,96,95};
    printarray(res,size);
}
//출처 : https://www.ibm.com/docs/en/zos/2.3.0?topic=only-variadic-templates-c11

    -> Base specifier list : base C에서 Pack expansion 확장

#include <iostream>
using namespace std;

struct a1{};
struct a2{};
struct a3{};
struct a4{};

template<class X> struct baseC{
    baseC() {printf("baseC primary ctor\n");}
};
template<> struct baseC<a1>{
    baseC() {printf("baseC a1 ctor\n");}
};
template<> struct baseC<a2>{
    baseC() {printf("baseC a2 ctor\n");}
};
template<> struct baseC<a3>{
    baseC() {printf("baseC a3 ctor\n");}
};
template<> struct baseC<a4>{
    baseC() {printf("baseC a4 ctor\n");}
};

template<class...A> struct container : public baseC<A>...{
    container(){
        printf("container ctor\n");
    }
};
//출처 : https://www.ibm.com/docs/en/zos/2.3.0?topic=only-variadic-templates-c11

    -> Member initializer list : class template container의 initializer 목록에서 Pack expansion 사용

#include <iostream>
using namespace std;

struct a1{};
struct a2{};
struct a3{};
struct a4{};

template<class X> struct baseC{
    baseC(int a) {printf("baseC primary ctor: %d\n", a);}
};
template<> struct baseC<a1>{
    baseC(int a) {printf("baseC a1 ctor: %d\n", a);}
};
template<> struct baseC<a2>{
    baseC(int a) {printf("baseC a2 ctor: %d\n", a);}
};
template<> struct baseC<a3>{
    baseC(int a) {printf("baseC a3 ctor: %d\n", a);}
};
template<> struct baseC<a4>{
    baseC(int a) {printf("baseC a4 ctor: %d\n", a);}
};

template<class...A> struct container : public baseC<A>...{
    container(): baseC<A>(12)...{
        printf("container ctor\n");
    }
};
//출처 : https://www.ibm.com/docs/en/zos/2.3.0?topic=only-variadic-templates-c11

    -> Template argument list : Pack expansion C...는 class template container에 대한 template argument list의 context에서 확장

#include <iostream>
using namespace std;

template<int val> struct value{
    operator int(){return val;}
};

template <typename...I> struct container{
    container(){
        int array[sizeof...(I)]={I()...};
        printf("container<");
        for(int count = 0; count<sizeof...(I); count++){
            if(count>0){
                printf(",");
            }
            printf("%d", array[count]);
        }
        printf(">\n");
    }
};

template<class A, class B, class...C> void func(A arg1, B arg2, C...arg3){
    container<A,B,C...> t1;  // container<99,98,3,4,5,6> 
    container<C...,A,B> t2;  // container<3,4,5,6,99,98> 
    container<A,C...,B> t3;  // container<99,3,4,5,6,98> 
}

    -> Exception specification list : Pack expantion X...가 exception specification list에서 확장

struct a1{};
struct a2{};
struct a3{};
struct a4{};
struct a5{};
struct stuff{};

template<class...X> void func(int arg) throw(X...){
    a1 t1;
    a2 t2;
    a3 t3;
    a4 t4;
    a5 t5;
    stuff st;
    
    switch(arg){
        case 1:
            throw t1;
            break;
        case 2:
            throw t2;
            break;
        case 3:
            throw t3;
            break;
        case 4:
            throw t4;
            break;
        case 5:
            throw t5;
            break;
        default:
            throw st;
            break;
    }        
}

 

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

[C++] Try / Catch _2  (0) 2021.06.24
[C++] Predefined Macro  (0) 2021.06.23
[C++] New_2  (0) 2021.06.21
[C++] Union  (0) 2021.06.18
[c++] inline  (0) 2021.06.16
  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 카카오스토리 공유하기