leesangwon0114

I am Research Engineer. Currently working in KT.

C++Template 20. variadic Template활용

22 Aug 2018 » c++

codenuri 강석민 강사 강의 내용기반으로 정리한 내용입니다.

result using variadic template

함수의 정보를 구하는 traits 만들기
  1. primary template 을 만들고 typedef T type 을 제공한다.
  2. 함수 타입인 T 안에 있는 리턴 타입(double)을 얻을 수 있도록 부분 특수화한다.
    • T -> R(A1, A2)
  3. 인자 개수에 제한을 없애기위해서 가변 인자 템플릿 사용.
    • T -> R(Types…)
#include <iostream>
using namespace std;

double hoo(short a, int b) {return 0;}

int goo() {return 0;}

template<typename T> struct result_type
{
	typedef T type;
}

template<typename R, typename ... Types> struct result_type<R(Types...)>
{
	typedef R type;
}

template<typename T>
void foo(const T& t)
{
	typename result_type<T>::type ret;

	cout << typeid(ret).name() << endl;
}

int main()
{
	foo(hoo);	// double
	foo(goo);	// int
}


result_type을 잘못사용했을 때 에러를 처리하는 방법

  1. typedef T type을 제공하지 않는다.
  2. static_assert()를 사용해서 에러 메시지 출력
  3. primary template 을 선언만 제공한다.
#include <iostream>
using namespace std;

double hoo(short a, int b) {return 0;}

int goo() {return 0;}

template<typename T> struct result_type 
//3 주석처리 : 선언부는 반드시 필요
/*
{
	// 1
	// typedef T type;
	// 2
	// static_assert(is_function<T>::value, "error");
}
*/


template<typename R, typename ... Types> struct result_type<R(Types...)>
{
	typedef R type;
}

template<typename T>
void foo(const T& t)
{
	typename result_type<T>::type ret;

	cout << typeid(ret).name() << endl;
}

int main()
{
	int n = 0;
	foo(n); // primary로 가서 그냥 int 나옴
}


argument using variadic template

함수의 정보를 구하는 traits 만들기

1.primary template 을 만들고 typedef T type 을 제공한다. 2.함수 타입인 T 안에 있는 함수 인자 타입을 얻을 수 있도록 부분 특수화한다.

  • T -> R(A1, A2), T -> R(A1, Types…)
#include <iostream>
using namespace std;

double hoo(short a, int b, char c) {return 0;}

template<size_t N, typename T> struct argument_type
{
	typedef T type;
}

template<typename R, typename A1, typename ... Types>
struct argument_type<0, R(A1, Types...)>
{
	typedef A1 type;
}

template<typename T>
void foo(const T& t)
{
	typename argument_type<0, T>::type ret;

	cout << typeid(ret).name() << endl;
}

int main()
{
	foo(hoo);	// double
	foo(goo);	// int
}


argument type에 0을 전달하지 않고 1, 2 를 전했을 때 구하는법

3.N번째 인자 타입 구하는 방법

  • 0번째 인자의 타입을 구하는 부분 특수화 작성
  • N번째 인자의 타입을 구하는 부분 특수화 작성하고 N==0이 될때까지 Recursive 를 사용한다(Recursive 사용시, 함수의 0번째 인자를 제거하고 N-1을 사용한다.)

argument_type<2, R(A1, A2, A3)>::type

재귀로 가면 앞에꺼 하나 버릴 수 있음

argument_type<1, R(A2, A3)>::type

argument_type<0, R(A3)>::type

0일 때는 부분 특수화 사용하니 type 구함

#include <iostream>
using namespace std;

double hoo(short a, int b, char c) {return 0;}

template<size_t N, typename T> struct argument_type
{
	typedef T type;
}

// N==0
template<typename R, typename A1, typename ... Types>
struct argument_type<0, R(A1, Types...)>
{
	typedef A1 type;
}

// N일때
template<size_t N, typename R, typename A1, typename ... Types>
struct argument_type<N, R(A1, Types...)>
{
	typedef typename argument_type<N-1, R(Types...)>::type type;
}

template<typename T>
void foo(const T& t)
{
	typename argument_type<2, T>::type ret;

	cout << typeid(ret).name() << endl;
}

int main()
{
	foo(hoo);	// double
	foo(goo);	// int
}


tuple using variadic template

tuple
  1. 서로 다른 타입의 객체를 N개 보관하는 템플릿.
  2. 요소를 접근할 때는 get 을 사용한다.
  3. C++11 부터 표준으로 제공. tuple 헤더
#include <iostream>
#include <tuple>
using namespace std;

int main()
{
	tuple<> t0;
	tuple<int> t1(1);
	tuple<int, double, int, char> t4(1, 3.4, 2, 'A');

	cout << get<2>(t4) << endl;	// 2
}



tuple 만들기.

1.가변 인자 템플릿을 사용해서 primary template 을 만든다.

#include <iostream>
#include <tuple>
using namespace std;

template<typename ... Types> struct xtuple
{
	static constexpr int N = 0;
}

int main()
{
	xtuple<> t0;
	xtuple<int> t1;
	xtuple<int, double, char> t3;
}


2.1개의 요소를 보관할 수 있도록 부분 특수화를 사용한다.

#include <iostream>
#include <tuple>
using namespace std;

template<typename ... Types> struct xtuple
{
	static constexpr int N = 0;
}

// 부분 특수화
template<typename T, typename ... Types> struct xtuple<T, Types...>
{
	T value;

	xtuple() = default;
	xtuple(const T& v) : value(v) {}
	static constexpr int N = 1;
}

int main()
{
	xtuple<> t0;
	xtuple<int> t1(3);
	xtuple<int, double, char> t3;
}


3.상속을 사용해서 N개를 보관할 수 있게 만든다.

#include <iostream>
#include <tuple>
using namespace std;

template<typename ... Types> struct xtuple
{
	static constexpr int N = 0;
}

// 부분 특수화
template<typename T, typename ... Types> struct xtuple<T, Types...> : public xtuple<Types...>
{
	T value;

	xtuple() = default;
	xtuple(const T& v, const Types& ... args) : value(v), xtuple<Types...>(args...) {}
	static constexpr int N = xtuple<Types...>::N + 1;
}

int main()
{
	xtuple<int, double, char> t3(1, 3.4, 'A');
	xtuple<double, char> t2;
	xtuple<char> t1;
}

Alt text


4.생성자등 필요한 멤버를 추가한다.

다음꺼에 get을 이용해 tuple 에서 값을 꺼내는 코드 설명함