文章最后给出了汇总的代码,可直接运行
1. typelist是什么
typelist是一种用来操作类型的容器。和我们所熟知的vector、list、deque类似,只不过typelist存储的不是变量,而是类型。
typelist简单来说就是一个类型容器,能够提供一系列的操作。
本文将展示使用元编程实现typelist。
2. 要实现的typelist的接口
在此列举一下即将要编写的typelist的所有接口:
- typelist:要实现的容器类型。
- front<typelist>:获取容器中的第一个元素。
- size<typelist>:获取容器的元素数量。
- pop_front<typelist, elem>:移出第一个元素。
- push_front<typelist, elem>:向开头插入一个元素。
- push_back<typelist, elem>:向结尾插入一个元素。
- replace_front<typelist, elem>:替换第一个元素。
- is_empty<typelist>:判断是否为空。
- find<typelist, index>:查找下标为index的元素。
- get_maxsize_type<typelist>:容器中尺寸(sizeof)最大的元素。
- reverse<typelist>:翻转容器中的元素。
3. 接口实现
3.1 容器
template<typename... Elems>
struct typelist{};
3.2 front<typelist>
template<typename TPLT>// typelist的简写
struct front;struct front<typelist<FirstElem, OtherElems...>>
{using type = FirstElem;
};
3.3 size<typelist>
template<typename TPLT>
struct size;template<typename... Elems>
struct size<typelist<Elems...>>
{static inline const value = sizeof...(Elems);
};
3.4 pop_front<typelist, elem>
template<typename TPLT>
struct pop_front;template<typename FirstElem, typename... OtherElems>
struct pop_front<typelist<FirstElem, OtherElems...>
{using type = typelist<OtherrElems...>;
};
3.5 push_front<typelist, elem>
template<typename TPLT, typename newElem>
struct push_front;template<typename... Elems, typename newElem>
struct push_front<typelist<Elems...>, newElem>
{using type = typelist<newElem, Elems...>;
};
3.6 push_back<typelist, elem>
template<typename TPLT, typename newElem>
struct push_back;template<typename... Elems, typename newElem>
struct push_back<typelist<Elems...>, newElem>
{using type = typelist<Elems..., newElem>;
};
3.7 replace_front<TPLT, elem>
template<typename TPLT, typename Elem>
struct replace_front;template<typename FirstElem, typename... OtherElems, typename Elem>
struct replace_front<typelist<FirstElem, OtherElems...>, Elem>
{using type = typelist<Elem, OtherElems...>;
};
3.8 is_empty<TPLT>
template<typename TPLT>
struct is_empty;template<typename... Elems>
struct is_empty
{static inline const bool value = sizeof...(Elems) == 0;
};
3.9 find<typelist, index>
template<typename TPLT, size_t index>
struct find : find<typename pop_front<TPLT>::type, index - 1>
{};template<typename TPLT>
struct find<TPLT, 0> :front<TPLT>
{
};
3.10 get_maxsize_type<typelist>
template<typename TPLT>
struct get_maxsize_type
{
private:using FirstType = typename front<TPLT>::type;using RemainLT = typename pop_front<TPLT>::type;using RemainMaxType = typename get_maxsize_type<RemainLT>::type;
public:using type = conditional_t < (sizeof(FirstType) > sizeof(RemainMaxType)),FirstType, RemainMaxType >;
};template<typename Elem>
struct get_maxsize_type<typelist<Elem>>
{using type = Elem;
};template<>
struct get_maxsize_type<typelist<>>;
3.11 reverse<typelist>
template<typename TPLT>
struct reverse
{
private:using FirstElem = typename front<TPLT>::type;using RemainTL = typename pop_front<TPLT>::type;using ReversedRemainTL = typename reverse<RemainTL>::type;
public:using type = typename push_back<ReversedRemainTL, FirstElem>::type;
};template<>
struct reverse<typelist<>>
{using type = typelist<>;
};
或
template<typename TPLT, bool = is_empty<TPLT>::value>
struct reverse;template<typename TPLT>
struct reverse<TPLT, false>
{
private:using FirstElem = typename front<TPLT>::type;using RemainTL = typename pop_front<TPLT>::type;using ReversedRemainTL = typename reverse<RemainTL>::type;
public:using type = typename push_back<ReversedRemainTL, FirstElem>::type;
};template<typename TPLT>
struct reverse<TPLT, true>
{using type = typelist<>;
};
4. 完整代码
#include <iostream>
#include <string>
#include "boost/type_index.hpp"using namespace std;template<typename T>
class TypeGetter
{
public:static inline const std::string name = boost::typeindex::type_id_with_cvr<T>().pretty_name();
};namespace myTypeList
{template<typename... T>struct typelist {};template<typename TPLT>struct front;template<typename FirstType, typename... Others>struct front < typelist<FirstType, Others...>>{using type = FirstType;};template<typename TPLT>struct size;template<typename... Args>struct size<typelist<Args...>>{static const inline size_t value = sizeof...(Args);};template<typename TPLT>struct is_empty;template<typename... Elems>struct is_empty<typelist<Elems...>>{static constexpr bool value = sizeof...(Elems) == 0;};template<typename TPLT>struct pop_front;template<typename FirstType, typename... Others>struct pop_front< typelist<FirstType, Others...> >{using type = typelist<Others...>;};template<typename TPLT, typename T>struct push_front;template<typename... Types, typename T>struct push_front<typelist<Types...>, T>{using type = typelist<T, Types...>;};template<typename TPLT, typename T>struct push_back;template<typename... Types, typename T>struct push_back<typelist<Types...>, T>{using type = typelist<Types..., T>;};template<typename TPLT, typename newElem>struct replace_front;template<typename FirstElem, typename... OtherElems, typename newElem>struct replace_front<typelist<FirstElem, OtherElems...>, newElem>{using type = typelist<newElem, OtherElems...>;};template<typename TPLT, size_t index>struct find : find<typename pop_front<TPLT>::type, index - 1>{};/*和下面的写法是等价的template<typename TPLT, size_t index>struct find{using type = typename find<typename pop_front<TPLT>::type, index - 1>::type;};*/template<typename TPLT>struct find<TPLT, 0> :front<TPLT>{};/*get_maxsize_type: 获取typelist中尺寸最大的类型*/template<typename TPLT>struct get_maxsize_type{private:using FirstType = typename front<TPLT>::type;using RemainLT = typename pop_front<TPLT>::type;using RemainMaxType = typename get_maxsize_type<RemainLT>::type;public:using type = conditional_t < (sizeof(FirstType) > sizeof(RemainMaxType)),FirstType, RemainMaxType >;};template<typename Elem>struct get_maxsize_type<typelist<Elem>>{using type = Elem;};template<>struct get_maxsize_type<typelist<>>;/*reverse: 翻转typelist*//*// 版本一template<typename TPLT>struct reverse{private:using FirstElem = typename front<TPLT>::type;using RemainTL = typename pop_front<TPLT>::type;using ReversedRemainTL = typename reverse<RemainTL>::type;public:using type = typename push_back<ReversedRemainTL, FirstElem>::type;};template<>struct reverse<typelist<>>{using type = typelist<>;};*/template<typename TPLT, bool = is_empty<TPLT>::value>struct reverse;template<typename TPLT>struct reverse<TPLT, false>{private:using FirstElem = typename front<TPLT>::type;using RemainTL = typename pop_front<TPLT>::type;using ReversedRemainTL = typename reverse<RemainTL>::type;public:using type = typename push_back<ReversedRemainTL, FirstElem>::type;};template<typename TPLT>struct reverse<TPLT, true>{using type = typelist<>;};
}class A {};int main()
{using TPL_1 = myTypeList::typelist<char, short, int, A, double>;using TPL_2 = myTypeList::typelist<>;cout << "TPL_1 的第一个类型为" << TypeGetter< myTypeList::front<TPL_1>::type >::name << endl;//cout << "TPL_2 的第一个类型为" << TypeGetter< myTypeList::front<TPL_2>::type >::name << endl;cout << "TPL_1 的size为:" << myTypeList::size<TPL_1>::value << endl;cout << "TPL_2 的size为:" << myTypeList::size<TPL_2>::value << endl;cout << "TPL_1 的pop_front为:" << TypeGetter< myTypeList::pop_front< TPL_1 >::type >::name << endl;//cout << "TPL_2 的pop_front为:" << TypeGetter< myTypeList::pop_front< TPL_2 >::type >::name << endl;cout << "TPL_1 push_front bool 为:" << TypeGetter< myTypeList::push_front<TPL_1, bool>::type>::name << endl;cout << "TPL_2 push_front bool 为:" << TypeGetter< myTypeList::push_front<TPL_2, bool>::type>::name << endl;cout << "TPL_1 push_back bool 为:" << TypeGetter< myTypeList::push_back<TPL_1, bool>::type>::name << endl;cout << "TPL_2 push_back bool 为:" << TypeGetter< myTypeList::push_back<TPL_2, bool>::type>::name << endl;cout << "TPL_1 replace_front with char 为:" << TypeGetter < myTypeList::replace_front< TPL_1, char >::type>::name << endl;cout << "TPL_1 index 2 type 为:" << TypeGetter< myTypeList::find<TPL_1, 2>::type > ::name << endl;cout << "TPL_1 max size type 为:" << TypeGetter<myTypeList::get_maxsize_type<TPL_1>::type>::name << endl;cout << "TPL_1 为:" << TypeGetter<TPL_1>::name << endl;cout << "TPL_1 reverse 为:" << TypeGetter<myTypeList::reverse<TPL_1>::type>::name << endl;return 0;
}
运行结果如下: