variadic template 은...
템플릿의 인자를 가변적으로 받을 수 있도록 구현하는 방식이다
variadic template을 함수 템플릿 / 클래스 템플릿 2가지로 나누어서 간략히 설명합니다.
| template<typename Arg1, typename... Args> // template parameter pack void Function( const Arg1& arg1, const Args&... args ) // function parameter pack { Test( arg1 ); Function( args... ); } void main() { Function( 1, "ezreal very handsome", 1.5f ); } | cs |
함수의 매개변수를 가변적으로 받기 위해 구현합니다.
2번 줄, 1번 주석 / template 타입을 정해줄 때 ... 를 붙이면 여러 개의 자료형을 가변적으로 받을 수 있다는 의미입니다.
3번 줄, 2번 주석 / 가변적으로 들어온 자료형에 대한 각각의 인자를 받는다는 의미입니다.
6번 줄 / Function( args... ); 를 통해 재귀함수를 호출하는 것을 알 수 있습니다.
재귀함수가 호출될 수록 args가 줄어듭니다.
가령, main에서 인자로 int, const char*, float 를 전달했다고 하면 ( 11번 줄)
arg1 은 int형 1이 들어오고
args 는 const char*형 "ezreal very handsome"와 float형 1.5f 가 들어옵니다.
여기서 Function( args... ); 함수를 호출해서 다시 Function함수가 호출되면
arg1 은 const char* 형 "ezreal very handsome"이 들어오고
args 는 float형 1.5f가 들어옵니다.
여기서 Function( args... ); 함수를 호출해서 다시 Function함수가 호출되면
arg1 은 float형 1.5f가 들어오고
args 는 void가 되서 없다고 취급됩니다. (이후로 나열된 자료형이 없으므로...)
마지막으로 재귀 호출을 종료할 void 함수를 만들어줌으로써 재귀를 탈출하도록 구현합니다.
(그래야 에러가 발생하지 않음 ▶ void가 되기 때문... )
ex) void Test() {}
참고) Test 함수는 매개변수로 넘어가는 자료형에 맞도록 오버로딩 구현이 되어있어야합니다. (당연한거지만..)
여기서도 Test함수 내부 하는 일이 똑같으면 함수 템플릿으로 구현할 수 있겠죵 ~~~~? ^_^*
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | class Base1 { public: Base1( int i ) {} } class Base2 { public: Base2( const char* str ) {} } class Base3 { public: Base3( float f ) {} } ///////////////////////////////////////////////// template<typename... BaseClass> class MyTest : public BaseClass... { public: MyTest( BaseClass&&... baseValues ) : BaseClass( baseValues )... { } } void main() { MyTest<Base1> t1( 2 ); MyTest<Base1, Base2> t2( 2, "ezreal very nice" ); MyTest<Base1, Base2, Base3> t3( 2, "ezreal very nice", 1.5f ); } | cs |
상속 관계에서, 어떤 클래스는 경우에 따라서 부모 클래스를 1개 가지거나, 2개 가지는 경우에 구현합니다.
(예제는 생성자 설명을 위해 3개로 했음...)
22번 줄 / <typename... BaseClass> 이렇게 함으로써, 여러 타입의 갯수를 가변적으로 받겠다는 의미입니다.
23번 줄 / public BaseClass... 이렇게 함으로써, 부모 클래스를 가변적으로 받겠다는 의미입니다.
중요한 것은 public BaseClass 한 덩어리가 반복된다는 의미입니다.
즉, public BaseA, public BaseB..... 라는 의미!
26번 줄 / 생성자 매개변수로 BaseClass&&... baseValuses 이렇게 되어있는데
마찬가지로 BaseClass 이게 하나의 타입이고, baseValues 이게 하나의 값입니다.
이것이 반복된다는 의미이므로, 이니셜라이즈에서도 BaseClass( baseValues ) 를 해줌으로써
한 덩어리에 대한 생성자를 초기화한다는 것입니다.
cf. && (유니버셜 레퍼런스) 에 대한 설명은 생략합니다.
(개인 메모. &&는 퍼펙트 포워딩과 관련있다. std::forward)
33번 줄 / 가변적으로 부모클래스를 상속받을 수 있는 것을 확인하기 위한 코드입니다.