leesangwon0114

I am Research Engineer. Currently working in KT.

C++Template 27. TemplateDesign_Typelist

03 Sep 2018 » c++

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


Typelist intro.

Andrei Alexandrescue, loki 라이브러리

Modern C++ Design 도 읽어보기

Typelist
  1. 값을 보관하지 않는다.
  2. N 개의 타입을 보관한다.

template<typename T, typename U> struct Typelist
{
	typedef T Head;
	typedef U Tail;
}

int main()
{
	Typelist<int, double> t1; 
	Typelist<int, Typelist<int, double>> t2; 
	Typelist<int, Typelist<int, Typelist<int, double>>> t3; 
}


Step2. NullType 와 매크로 도입

Typelist: 타입을 여러개 보관하는 type의 list(값이 아님.)


template<typename T, typename U> struct Typelist
{
	typedef T Head;
	typedef U Tail;
}

struct NullType{};

// 매크로 도입

#define TYPELIST_1(T1) Typlelist<T1, NullType>;
#define TYPELIST_2(T1, T2) Typlelist<T1, Typelist<T2, NullType>>;
#define TYPELIST_3(T1, T2, T3) Typlelist<T1, Typelist<T2, Typelist<T3, NullType>>>;
#define TYPELIST_4(T1, T2, T3, T4) Typlelist<T1, Typelist<T2, Typelist<T3, Typelist<T4, NullType>>>>;

int main()
{
	Typelist<int, NullType> t1;
	Typelist<int, Typelist<double, NullType>> t2;
	Typelist<int, Typelist<double, Typelist<char, NullType>>> t3;

	// 매크로 도입
	TYPELIST_4(int, double, char, short) t4;
}



template<typename T, typename U> struct Typelist
{
	typedef T Head;
	typedef U Tail;
}

struct NullType{};

// 매크로 도입

#define TYPELIST_1(T1) Typlelist<T1, NullType>;
#define TYPELIST_2(T1, T2) Typlelist<T1, Typelist<T2, NullType>>;
#define TYPELIST_3(T1, T2, T3) Typlelist<T1, Typelist<T2, Typelist<T3, NullType>>>;
#define TYPELIST_4(T1, T2, T3, T4) Typlelist<T1, Typelist<T2, Typelist<T3, Typelist<T4, NullType>>>>;

//---------------------------------------------------------------------

template<typename T> class xtuple {};

int main()
{
	// xtuple<int> t1;

	xtuple<TYPELIST_3(int, double, char)> t1;
}


Typelist Length

#include <iostream>
using namespace std;

template<typename T, typename U> struct Typelist
{
	typedef T Head;
	typedef U Tail;
}

struct NullType{};

#define TYPELIST_1(T1) Typlelist<T1, NullType>;
#define TYPELIST_2(T1, T2) Typlelist<T1, Typelist<T2, NullType>>;
#define TYPELIST_3(T1, T2, T3) Typlelist<T1, Typelist<T2, Typelist<T3, NullType>>>;
#define TYPELIST_4(T1, T2, T3, T4) Typlelist<T1, Typelist<T2, Typelist<T3, Typelist<T4, NullType>>>>;

//---------------------------------------------------------------------
// Typelist의 요소 갯수 구하기.

// 1. 사용하는 모습을 보고 primary template 작성
template<typename T> struct Length
{
	// enum { value = ? }; // constexpr value 를 요즘에는 많이 사용
}

// 2. 갯수를 구할 수 있도록 부분 특수화
template<typename T, typename U> struct Length<Typelist<T, U>>
{
	enum { value = Length<U>::value + 1 };
}

// 3. 재귀를 종료 하기 위한 전문화
template<> struct Length<NullType>
{
	enum { value = 0 };
}

template<typename T> void test() 
{
	cout << Length<T>::value << endl; // 4

};

int main()
{
	test<TYPELIST_4(int, char, short, double)>();
}


TypeAt

#include <iostream>
using namespace std;

template<typename T, typename U> struct Typelist
{
	typedef T Head;
	typedef U Tail;
}

struct NullType{};

#define TYPELIST_1(T1) Typlelist<T1, NullType>;
#define TYPELIST_2(T1, T2) Typlelist<T1, Typelist<T2, NullType>>;
#define TYPELIST_3(T1, T2, T3) Typlelist<T1, Typelist<T2, Typelist<T3, NullType>>>;
#define TYPELIST_4(T1, T2, T3, T4) Typlelist<T1, Typelist<T2, Typelist<T3, Typelist<T4, NullType>>>>;

//---------------------------------------------------------------------
// Typelist의 N 번째 요소의 타입 구하기.

// 1. 사용하는 코드를 보고 primary template 작성
// T: Typelist
template<typename T, int N> struct TypeAt;

// 2. 원하는 타입을 구할 수 있도록 부분 특수화
// T: Typelist 의 요소 타입
/*
template<typename T, typename U, int N> struct TypeAt<Typelist<T, U>, N>
{
	typedef ? type; // 여기서 현재 타입을 채울 수 없음
}
*/

// N==0 일때.
template<typename T, typename U, int N> struct TypeAt<Typelist<T, U>, 0>
{
	typedef T type;
}

// N!=0 일때.
template<typename T, typename U, int N> struct TypeAt<Typelist<T, U>, N>
{
	typedef typename TypeAt<U, N-1>::type type;
}

template<typename T> void test() 
{
	// typename TypeAt<T, 0>::type n;
	typename TypeAt<T, 1>::type n;
	cout << typeid(n).name() << endl;
};

int main()
{
	test<TYPELIST_4(int, char, double, long)>();
}


Append

#include <iostream>
using namespace std;

template<typename T, typename U> struct Typelist
{
	typedef T Head;
	typedef U Tail;
}

struct NullType{};

#define TYPELIST_1(T1) Typlelist<T1, NullType>;
#define TYPELIST_2(T1, T2) Typlelist<T1, Typelist<T2, NullType>>;
#define TYPELIST_3(T1, T2, T3) Typlelist<T1, Typelist<T2, Typelist<T3, NullType>>>;
#define TYPELIST_4(T1, T2, T3, T4) Typlelist<T1, Typelist<T2, Typelist<T3, Typelist<T4, NullType>>>>;

//---------------------------------------------------------------------
// Typelist의 끝에 타입 추가하기

template<typeanme TL, typename T> struct Append;

// TL, T
// 1. NullType, NullType => NullType
template<> struct Append<NullType, NullType>
{
	typedef NullType type;
}

// 2. NullType, 임의의 타입 => TypeList<임의의타입, NullType>
template<typename T> struct Append<NullType, T>
{
	typedef TypeList<T, NullType> type;
}

// 3. NullType, TypeList<Head, Tail> => TypeList<Head, Tail>
template<typename Head, typename Tail> struct Append<NullType, TypeList<Head, Tail>>
{
	typedef TypeList<Head, Tail> type;
}

// 4. TypeList<Head, Tail>, NullType => TypeList<Head, Tail>
template<typename Head, typename Tail> struct Append<TypeList<Head, Tail>, NullType>
{
	typedef TypeList<Head, Tail> type;
}

// 5. TypeList<Head, Tail>, 임의의 타입 => Typelist<Head, Append<Tail, T>::type>
template<typename Head, typename Tail, typename T> struct Append<TypeList<Head, Tail>, T>
{
	typedef Typelist<Head, Append<Tail, T>::type> type;
}

template<typename T> void test() 
{
	typename Append<T, int>::type t1;
	cout << typeid(t1).name() << endl; // int, char, double, int, NULL
};

int main()
{
	test<TYPELIST_4(int, char, double)>();
}


using Typelist

#include <iostream>
using namespace std;

template<typename T, typename U> struct Typelist
{
	typedef T Head;
	typedef U Tail;
}

struct NullType{};

#define TYPELIST_1(T1) Typlelist<T1, NullType>;
#define TYPELIST_2(T1, T2) Typlelist<T1, Typelist<T2, NullType>>;
#define TYPELIST_3(T1, T2, T3) Typlelist<T1, Typelist<T2, Typelist<T3, NullType>>>;
#define TYPELIST_4(T1, T2, T3, T4) Typlelist<T1, Typelist<T2, Typelist<T3, Typelist<T4, NullType>>>>;

// Holder : 임의의 타입의 data 하나 보관..
template<typename T> struct Holder
{
	T value;
}

// GenScatterHierachy => MakeCode

template<typename T, template<typename> class Unit> class MakeCode : public Unit<T>
{
}

template<typename T, template<typename> class Unit> class MakeCode<NuullType, Unit>
{
}

int main()
{
	Holder<int> h1;

	MaekCode<int, Holder> mc1; // 기반 클래스 Holder<int> 이므로 Holder<int> 와 메모리 모양이 동일

	MakeCode<double, Holder> mc2; // Holder<double>
	MakeCode<NullType, Holder> mc3; // empty
}

#include <iostream>
using namespace std;

template<typename T, typename U> struct Typelist
{
	typedef T Head;
	typedef U Tail;
}

struct NullType{};

#define TYPELIST_1(T1) Typlelist<T1, NullType>;
#define TYPELIST_2(T1, T2) Typlelist<T1, Typelist<T2, NullType>>;
#define TYPELIST_3(T1, T2, T3) Typlelist<T1, Typelist<T2, Typelist<T3, NullType>>>;
#define TYPELIST_4(T1, T2, T3, T4) Typlelist<T1, Typelist<T2, Typelist<T3, Typelist<T4, NullType>>>>;

// Holder : 임의의 타입의 data 하나 보관..
template<typename T> struct Holder
{
	T value;
}

// GenScatterHierachy => MakeCode

template<typename T, template<typename> class Unit> class MakeCode : public Unit<T>
{
}

template<typename T, template<typename> class Unit> class MakeCode<NuullType, Unit>
{
}

// MakeCode의 1번째 인자가 Typelist 일 때..
template<typename T, template<typename> class Unit>
 //= MakeCode<int, Unit>, MakeCode<Typelist<double, NullType>
 //=  Holder<int>, MakeCode<double, Unit>, MakeCode<NullType, Unit> 
 //= Holder<int>, Holder<double>, empty
class MakeCode<Typelist<Head, Tail>, Unit> : public MakeCode<Head, Unit>, public MakeCode<Tail, Unit>
{
	// int value;
	// double value;
}

int main()
{
	// MakeCode 의 1번째 인자가 Typelist 일 때..
	//			Typelist<int, Typelist<double, NullType>>
	MakeCode<TYPELIST_2(int, double), Holder> m;

	MaekCode<int, Holder> mc1; // Holder<int>
	MakeCode<double, Holder> mc2; // Holder<double>
	MakeCode<NullType, Holder> mc3; // empty
}