C++模板元编程----堆排序
目录
前言
经过前两次经验的积累,终于来到了麻烦的堆排序。在一开始接触模板元编程的时候,我就期望有一天能够写出元编程堆排序的代码。原因是看了知乎大佬的一篇文章《在简历上写了“精通 C++”后……》。由于学识浅薄,感觉只能接触到模板元编程这一部分,所以便开始了对模板元编程的研究。经过多次的学习研究,最终在今天完成了这一成就。但是时间花了三个小时左右,所以时间肯定是不能达标了,但是也算是一个比较奇特的经历吧。
相比较于前两种排序方式,堆排序需要交换操作,更多的判断操作,随机读取等。这一些都不是模板元编程擅长的地方,但是幸运的是都是有办法实现。
实现的一些小细节
Debug
前两次实现的时候,运气很好,结束的时候都没有出现什么bug,但是这一次的比较麻烦,出现了比较严重的bug。但是由于限制,没办法进行很好的调试。于是通过编译器的报错机制,我写了一个元编程的断言。当输入的flag为false时,便会报错。
template<bool>
struct m_assert;
template<>
struct m_assert<true> {
typedef int result_type;
};
template<>
struct m_assert<false> {};
使用的时候在需要查看的类里面,放入一个类似的语句,然后将flag改成相应的条件,就可以得到调用栈了。
typename m_assert<m_or<begin != 0, T::size != 3>::result>::result_type non_data;
实现的方法也很简单,就是区分true和false,当输入为true时,结构体便有result_type类型,而false则没有。此时如果使用其的result_type,便会产生报错,以便观察程序的调用。编译输出为:

但是这一种方法没办法打印当前调用的输出,因此我又增加了一层:
template<bool flag, typename ...T>
struct m_assert_print{
typedef typename m_assert<flag>::result_type result_type;
};
使用方法也类似,如果需要打印当前调用的输出,便将要打印的内容作为T输入即可,譬如:
typename m_assert_print<m_or<begin != 0, T::size != 3>::result, result_type>::result_type non_data;
此时的编译输出为:

可以看到相比较之前的输出,这一次的输出多了一层,而在这一层里,包含了需要打印的内容。
惰性求值
我一开始一直以为C++是没有实现惰性求值的,但是经过一系列的实验,和查找资料,好像C++是存在一定的惰性求值的。譬如
template<>
struct m_assert<false> {};
template<bool flag, typename ...T>
struct m_assert_print{
typedef typename m_assert<flag>::result_type result_type;
};
template<bool flag>
struct ErrorType {
typedef typename m_assert<flag>::result_type result_type;
};
struct Test {
typedef typename m_if<true, ErrorType<true>, ErrorType<false>>::result_type::result_type result_type;
};
如果是没有惰性求值的存在,这一段代码是应该报错的。因为在ErrorType<false>中引用了m_assert<fasle>::result_type。而在上一部分就提到过,应该是会必报错的。
而对于另一个写法
struct Test {
typedef typename m_if<true, ErrorType<true>::result_type, ErrorType<false>::result_type>::result_type result_type;
};
编译期却提示错误,甚至将ErrorType模板修改成
template<bool flag>
struct ErrorType {
typedef typename m_assert<flag>::result_type result1_type;
typedef int result_type;
};
编译器也还是会报错。
通过查阅资料总结的话,编译期对于出现的模板并不会全部的具现化。但是如果使用了其中的类型,便会对其进行具现化[1]。因此,通过这个特性,是有办法设计出一些惰性加载的类,但是由于当时并不知道,所以实现的时候采取了偏特化的方法,防止编译时走向一些奇怪的方向。
简单的来说,就是通过增加一个valid输入,来判断需不需要对这个支线进行下去。如果为fasle,则返回默认值,如果为true,则返回操作后的值,配合m_if,便可以得到想要的结果。
总结
总的来说,模板元编程是C++里面一个比较有趣的部分。由于其晦涩难懂,也成为了许多大佬秀操作的地方。但是随着C++标准的完善,它的难度也在不断的降低。在C++17的时候,大部分的函数都可以使用constexpr来修饰了,这让模板元编程在值运算的时候失去了一部分函数式编程的特点。而C++20中的constraints和concepts,让模板偏特化有了更大的活力。
源代码:https://gist.github.com/ink19/9fdcca26e89655e8c1b80da56ee04c65
Ref
[1] https://www.jianshu.com/p/f2477d2c19ea
博客原文:https://www.cnblogs.com/ink19/p/cpp_template_heap_sort.html
C++模板元编程----堆排序的更多相关文章
- C++模板元编程(C++ template metaprogramming)
实验平台:Win7,VS2013 Community,GCC 4.8.3(在线版) 所谓元编程就是编写直接生成或操纵程序的程序,C++ 模板给 C++ 语言提供了元编程的能力,模板使 C++ 编程变得 ...
- C++模板元编程 - 函数重载决议选择工具(不知道起什么好名)完成
这个还是基于之前实现的那个MultiState,为了实现三种类型“大类”的函数重载决议:所有整数.所有浮点数.字符串,分别将这三种“大类”的数据分配到对应的Converter上. 为此实现了一些方便的 ...
- C++模板元编程 - 挖新坑的时候探索到了模板元编程的新玩法
C++真是一门自由的语言,虽然糖没有C#那么多,但是你想要怎么写,想要实现什么,想要用某种编程范式或者语言特性,它都会提供. 开大数运算类的新坑的时候(又是坑),无意中需要解决一个需求:大数类需要分别 ...
- 读书笔记_Effective_C++_条款四十八:了解模板元编程
作为模板部分的结束节,本条款谈到了模板元编程,元编程本质上就是将运行期的代价转移到编译期,它利用template编译生成C++源码,举下面阶乘例子: template <int N> st ...
- c++ 模板元编程的一点体会
趁着国庆长假快速翻了一遍传说中的.大名鼎鼎的 modern c++ design,钛合金狗眼顿时不保,已深深被其中各种模板奇技淫巧伤了身...论语言方面的深度,我看过的 c++ 书里大概只有 insi ...
- C++模板元编程 - 3 逻辑结构,递归,一点列表的零碎,一点SFINAE
本来想把scanr,foldr什么的都写了的,一想太麻烦了,就算了,模板元编程差不多也该结束了,离开学还有10天,之前几天部门还要纳新什么的,写不了几天代码了,所以赶紧把这个结束掉,明天继续抄轮子叔的 ...
- C++模板元编程 - 2 模仿haskell的列表以及相关操作
这是昨天和今天写的东西,利用C++的可变模板参数包以及包展开,模式匹配的一些东西做的,感觉用typename...比轮子叔那个List<A,List<B, List<C, D> ...
- 一道模板元编程题源码解答(replace_type)
今天有一同学在群上聊到一个比较好玩的题目(本人看书不多,后面才知是<C++模板元编程>第二章里面的一道习题), 我也抱着试一试的态度去完成它, 这道题也体现了c++模板元编程的基础和精髓: ...
- effective c++ Item 48 了解模板元编程
1. TMP是什么? 模板元编程(template metaprogramming TMP)是实现基于模板的C++程序的过程,它能够在编译期执行.你可以想一想:一个模板元程序是用C++实现的并且可以在 ...
随机推荐
- PyQt(Python+Qt)学习随笔:字体writingSystem、ProportionalFonts、MonospacedFonts的含义以及QFontComboBox字体组合框详解
专栏:Python基础教程目录 专栏:使用PyQt开发图形界面Python应用 专栏:PyQt入门学习 老猿Python博文目录 一.引言 在介绍QFontComboBox之前,我们先简单介绍一下字体 ...
- x++ 和 ++x的区别
很多编程语言都会有x++和++x的问题,两个到底是怎么回事? 一个先执行一个后执行的区别 var x = 0; console.log(x++);//0 遇到x++当前执行值不变 console.lo ...
- Devpress (DxReport)使用ReportDesigner (一) 基本功能
1. Devpress (DxReport)编辑 (1) 新建一个XtraReport. (2) 在报告上点右键添加元素: 元素说明: (1) 其中有报告头,报告尾,页头,页尾,组头,组尾,详细. ...
- NOI2008 志愿者招聘
文化课 + 竞赛双废物又来水题解了. 首先,对于题干中的人,很像网络流中的流量,但是他有一个每天人数的下限,我从网上借鉴(chaoxi)到了两种思路: 把下界限制转化为一条边的流量下界,这样就是最小费 ...
- sql注入之union注入
联合查询注入利用的前提: 必须要有回显 联合查询过程: 判断是否存在注入点 判断是什么类型注入(字符型or数字型) 判断闭合方式 查询列数个数(order by) 5, 获得数据库名 获得表名 获得字 ...
- github拉去代码慢的处理方式(最简单)
https://github.com/xxx/xxxx 替换成 https://github.com.cnpmjs.org/xxx/xxxx 再去拉取,速度快很多,亲测可用
- JavaSE05-数组
1.概念 同一种类型数据的集合.其实数组就是一个容器. 2.优点 可以自动给数组中的元素从0开始编号,方便操作这些元素. 3.格式 1 元素类型[] 数组名 = new 元素类型[元素个数或数组长度] ...
- 淘宝|蚂蚁|菜鸟|盒马|嘀嘀|饿了么面经(已拿多个offer)
上一篇的同学拿到了bigo和腾讯的offer,这一次的分享来自两位同学的面试综合,他们分别拿到了菜鸟.嘀嘀.盒马的多个offer,由于面试的时间跨度时间太长,且面试的部门太多,只能回忆到具体的面试题, ...
- C#实现SHA256WithRSA加密用于Java的秘钥私钥
首先要把Java秘钥进行转换,然后再进行加密 转制秘钥的方法 public static string RSAPrivateKeyJava2DotNet(string privateKey) { Rs ...
- Hive JDBC执行load时无法从本地加载数据
通过hive-jdcv连接hive server,在应用服务端执行以下命令,报错:Hiver Server节点上找不到data.txt load data local inpath '/home/dw ...