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++实现的并且可以在 ...
随机推荐
- 第12.1节 Python os模块导览
os 模块提供了许多与操作系统交互的函数,一定要使用 import os 而不是 from os import * ,这将避免内建的 open() 函数被 os.open() 隐式替换掉,它们的使用方 ...
- Project Lombok——带给你简洁、清晰的代码
相信但凡有一点Java编程经历的人,都见过或者写过下面这种代码.这是一个简单的POJO,只有4个fields,加上构造器.equals.hash.toString以及各种getter setter,前 ...
- 测试window安装的客户端
1.win10 安装了客户端,测试一下,
- Kruskal重构树——[NOI2018] 归程
题目链接: UOJ LOJ 感觉 Kruskal 重构树比较简单,就不单独开学习笔记了. Statement 给定一个 \(n\) 点 \(m\) 边的无向连通图,用 \(l,a\) 描述一条边的长度 ...
- 题解-CF755G PolandBall and Many Other Balls
题面 CF755G PolandBall and Many Other Balls 给定 \(n\) 和 \(m\).有一排 \(n\) 个球,求对于每个 \(1\le k\le m\),选出 \(k ...
- 题解-洛谷P4229 某位歌姬的故事
题面 洛谷P4229 某位歌姬的故事 \(T\) 组测试数据.有 \(n\) 个音节,每个音节 \(h_i\in[1,A]\),还有 \(m\) 个限制 \((l_i,r_i,g_i)\) 表示 \( ...
- qq 表情库
![/qq](https://cdn.luogu.com.cn/upload/pic/62224.png) ![/cy](https://cdn.luogu.com.cn/upload/pic/622 ...
- Clickhouse 在大数据分析平台 - 留存分析上的应用
导语 | 本文实践了对于千万级别的用户,操作总数达万级别,每日几十亿操作流水的留存分析工具秒级别查询的数据构建方案.同时,除了留存分析,对于用户群分析,事件分析等也可以尝试用此方案来解决. 文章作者: ...
- JVM的艺术—JAVA内存模型
*喜欢文章,动动手指点个赞 * 引言 亲爱读者你们好,关于jvm篇章的连载,前面三章讲了类加载器,本篇文章将进入jvm领域的另一个知识点,java内存模型.彻底的了解java内存模型,是有必要的.只要 ...
- [日常摸鱼]bzoj1036 [ZJOI2008]树的统计Count
听说后天会考x 省选居然还考模板题的么(好吧好像NOI也有考而且也是树剖-) 题意:一棵树,每个点有权值,三种操作:单点修改.求链上最大值.求链上权值和. 直接上模板. 我可能不会写单点修改的线段树了 ...