在函数式语言中list基本都是递归式结构,类似:{elem, {elem, {elem, ...}}}
。
可以看到,基本结构是一个二元组{Head, Tail}
,Head是一个list节点,第二个元素Tail仍旧是一个类似的二元组,如此递归。
对于模板元编程无论list元素还是list本身都是类型,所以我们定义模板元编程的list结构如下:
// "tlp/list/TypeElem.h"
template<typename H, typename T>
struct TypeElem
{
using Head = H;
using Tail = T;
};
#define __type_elem(...) TypeElem<__VA_ARGS__>
有了TypeElem
,我们对其组合就得到了元素是类型的list。例如:
using List = TypeElem<char, TypeElem<int, TypeElem<long, TypeElem<short,NullType>>>>;
上例中,List是一个长度为4的类型列表,它的元素分别是char、int、long、short。最后的NullType是一个占位符,我们用它表示list的结束。
如果使用宏的版本,可以写的稍微好看些:
using List = __type_elem(char, __type_elem(int, __type_elem(long, __type_elem(short, __null()))));
上述列表的结构虽然非常简单,但是写起来却十分繁琐。在定义list的时候要不停重复__type_elem
,非常不简洁。下面我们提供一个构造元函数,用来简化对list的定义。
// "tlp/list/algo/TypeList.h"
template<typename Head, typename ...Tails>
struct TypeList
{
using Result = TypeElem<Head, typename TypeList<Tails...>::Result>;
};
template<typename H>
struct TypeList<H>
{
using Result = TypeElem<H, NullType>;
};
#define __type_list(...) typename TypeList<__VA_ARGS__>::Result
如上TypeList是一个元函数,它通过变长模板参数来构造一个所有元素是类型的list结构。现在可以这样定义list:__type_list(char, int, long, short)
,看起来非常的简单直观。
另外,对于全是数值的list,如 __type_list(__int(0), __int(1), __int(2))
的写法也可以再简单一些。如下我们提供了一个__value_list()
的语法糖。
// "tlp/list/algo/ValueList.h"
template<int Head, int ...Tails>
struct ValueList
{
using Result = TypeElem<IntType<Head>, typename ValueList<Tails...>::Result>;
};
template<int H>
struct ValueList<H>
{
using Result = TypeElem<IntType<H>, NullType>;
};
#define __value_list(...) typename ValueList<__VA_ARGS__>::Result
现在可以这样定义:__value_list(0, 1, 2, 3)
,其本质和__type_list(__int(0), __int(1), __int(2))
是一样的。
TEST("test value list")
{
ASSERT_EQ(__value_list(0, 1,2), __type_list(__int(0), __int(1), __int(2)));
};