参考链接:https://github.com/MagicBowen/tlp/tree/master/include/tlp、C++11 模板元编程 - 目录 - 简书
一、数值结构具体代码实现:https://github.com/pisuto/tinySTLLearning/tree/master/Test/TemplatemetaProgramLearning
在实现快速排序之前,首先是定义存储数据的类型结构。在模板元编程中,每一个值其实是使用一个一个类型表示,那么就需要定义一个类,作为所有数值类型的父类。派生类只要使用父类定义的值和类型即可。
// num type
template
struct num_type
{
using value_type = T;
static constexpr T value = N;
};
template
struct int_type : num_type {};
// bool
template
struct bool_type : num_type {};
二、基本的操作类
在定义了数值类型之后,对这些数值的操作是必不可少的,类似于函数一样。以数值比较为例子,对于>=的操作是需要通过模板来实现的,因为数值类型本身就是类。另外>大于号好像在模板中不能被区分。
templatestruct type_greater { // >大于号好像不能很好区分 using result = bool_type < T::value < H::value>; }; // 尝试实现其他的模板类型 // type_add 实现数值叠加并获得结果 // type_is_same 判断两个类型是否一致 // type_negate 对bool_type类型进行取反 // ... ... //
除了一些数值操作类的函数的实现,也需要实现有if和for语句功能的模板类。这里的if语句使用模板特化来实现,通过true_result和false_result来进行区分。而for循环(放在讲list的时候重点讲解)则是需要通过递归来实现。
using false_result = bool_type; using true_result = bool_type ; // 根据结果选择不同的分支 template struct type_is_choose; template struct type_is_choose { using result = H; }; template struct type_is_choose { using result = T; };
对于判断两个类型是否可以互相转化也可以通过模板来实现,这里最主要的是采用函数重载来实现不同类型的区分。“...”表示的是可以输入任意个数的形参。需要注意的是其中的注释部分,如果仅仅是用返回值给bool_type赋值这是有问题的,因为其是在运行时决定的,这里必须是在编译时就决定,因此采用size_of来处理。
templatestruct type_is_convertible { //private: // static D self(); // static bool test(...) { return false; }; // static bool test(B) { return true; }; //public: // // 这种方法不行是因为返回值是在运行时候决定的 // using result = bool_type ; private: using Yes = char; struct No { char dummy[2]; }; static Yes test(B); static No test(...); static D self(); public: using result = bool_type ; };
类似地,还有type_is_base_of来判断一个类是否是另一个类的基类,那么就可以用type_is_convertible来判断D*是否可以向B*进行转换。需要注意的是D和B不能是同一类型,否则就不符合该类型的意义。另外,两个类的类型不能都是void*。
templatestruct type_is_base_of { private: using condition_not_same_type = typename type_and< typename type_negate ::result>::result, typename type_negate ::result>::result>::result; public: using result = typename type_and ::result>::result;
其余还有许多用于操作的类,必须自己学会动手实现。
// 两个数值类型的值是否相等
type_is_equal
// 为bool_type结果取反
type_negate
// 为两个bool_type结果取与
type_and
// 判断类型是否有效得到bool_type
type_is_valid
// 实现>=
type_greater_equal
//
// ... ...
三、使用模板实现LIST
为了存储一组数据,在常规的操作中是创建一个数组变量,例如new int[5]或者直接使用std::vector。而在模板中要存储变量必须在类型里面进行嵌套,而数值则是作为一个模板参数存在。因此,需要创建一个类型用于连接前后的数据(其实从这里可以看出,相对于list里的元素,这个数据结构更像是单链表里的node),即:
templatestruct type_elem { using head = H; // 真正保存的数据 using tail = T; // 连接后续的数据 }; // null struct null_type {};
这里的模板参数是一个类型,那么要怎么存储数据呢?这就用到了前面定义的数值类型int_type。
以存储一个数据为例子:type_elem<1, null_type>
以存储两个数据为例子:type_elem<1, type_elem<2, null_type>>
以存储三个数据为例子:type_elem<1, type_elem<2, type_elem<3, null_type>>>
从中可以看到数据是以递归的形式一层嵌套一层存在的,那么和函数里的递归一样需要递归函数和终止条件。
template四、LIST的工具类struct type_list { using result = type_elem ::result>; // static constexpr auto size = sizeof(Ts)...; }; template struct type_list { using result = type_elem ; }; // for example using list = typename type_list , int_type<1>, int_type<2>, int_type<0>, int_type<3>>::result;
在完成list的定义之后,为了完成快速排序,还需要编写类似于原生list、vector等容器的工具函数一样的工具类。
以push为例子,在list最后添加一个元素,那么就需要遍历list直至末尾,并加上一个type_elem类。同理的append结合两个list也是如此,在最后末尾添加上list2即可。
// push
template
struct type_push;
template
struct type_push
{
using result = typename type_elem;
};
template<>
struct type_push
{
using result = null_type;
};
template
struct type_push, V>
{
using result = type_elem::result>;
};
// append
template
struct type_append;
template
struct type_append, TL2>
{
using result = type_elem;
};
template
struct type_append, TL2>
{
using result = typename type_elem::result>;
};
为了实现quick_sort,其中的筛选操作是必不可少的,通过type_filter应用某一规则获得适应该规则的所以元素形成list,丢弃所以不满足规则的元素。这就必须使用二选一的操作类,即前文构建的type_is_choose。
templateclass Pred> struct type_filter; template class Pred> struct type_filter { using result = null_type; }; template class Pred> struct type_filter , V, Pred> { using result = typename type_is_choose ::result, type_elem ::result>, typename type_filter ::result>::result; };
// 还有许多工具类 // // 获取list的长度 type_length // 获取某一位置的元素 type_at // 元素是否被包含 type_is_included // 删除某一元素 type_erase // 去除重复的元素 type_unique // 判断list1是否是list2的子集 type_is_subset // ... ...五、快速排序
参考连接:别再问我 C++ 里怎么写快速排序(雾) - 知乎
实际上用函数写快速排序就是一个简单的思想,将数据集以主元为标准将小于主元的数放在主元的左边,将大的数放在主元的右边,然后再在这两数据集中继续递归,即:
那么就依照以上的思想就可以在模板中实现快速排序。
templatestruct type_quick_sort; template<> struct type_quick_sort { using result = null_type; }; template struct type_quick_sort > { using result = typename type_append< typename type_push ::result, H, type_less>::result, H>::result, typename type_filter ::result, H, type_greater_equal>::result >::result; }; // 切记不能忘记result using quick_sort = typename type_quick_sort ::result;



