多一些Aha Time,发现技术的美妙🍺|

啊原来是这样呀

园龄:8年3个月粉丝:3关注:9

【C++】17.元编程[深蓝学院C++第15章]

前言

 

一.元编程的引入

1.1 从泛型编程到元编程

 

泛型编程:使用一套代码处理不同的类型

对于特殊的类型需要引入额外的处理逻辑——引入操纵程序的逻辑

元编程与编译器计算,对于cpp而言元编程可以看做为了作编译期计算

1.2 元程序示例

1991年,Erwin Unruh编写的程序,在编译错误中产生质数

1.3 使用编译器运算辅助运行期计算

不是简单地将整个运算一分为二

详细分析哪些内容可以放到编译器,哪些需要放到运行期,如果某些信息需要在运行期确定则无法利用编译期计算

1.4 元程序的形式

1 constexpr int fun(int x){
2     return x + 1;
3 }
4 constexpr int val = fun(3);
5 
6 int main(){
7     return val;
8 }

如上,在编译期已经完成了x+1的计算

模板,constexpr函数,其他编译器可使用的函数如sizeof,sizeof(int)

通常以函数为单位,也被称为函数式编程

1.5 元数据

基本元数据:数值、类型、模板

数组

1.6 元程序的性质

输入输出均为“常量”,不能引入变量

函数无副作用,即不同时期的调用不会发生改变

1.7 #include <type_traits>元程序库

is_same_v、 is_class等等

二.顺序、分支、循环代码的编写方式

2.1 顺序代码的编写方式

代码无需置于函数中,通常置于模板中,以头文件的方式提供。

类型转换示例:为输入类型去掉引用并添加const

复制代码
 1 #include <iostream>
 2 #include <type_traits>
 3 
 4 template <typename T>
 5 struct Fun{
 6     using RemRef= typename std::remove_reference<T>::type;
 7     using type = typename std::add_const<RemRef>::type;
 8 };
 9 
10 int main(){
11     Fun<int&>:: type x = 3;
12 }
复制代码

输入数值、类型,返回数值、类型:

复制代码
 1 #include <iostream>
 2 #include <type_traits>
 3 
 4 template <typename T,int S>
 5 struct Fun{
 6     using RemRef= typename std::remove_reference<T>::type;
 7     constexpr static int value = sizeof(T) - S;
 8 };
 9 
10 int main(){
11     Fun<int&,4>::RemRef x;
12     std::cout << Fun<int&,4>::value << std::endl;
13     std::cout << Fun<double&,4>::value << std::endl;
14 }
复制代码

通过别名模板简化调用方式

constexpr auto Fun = Fun_<int&,S>::value;

2.2 分支代码的编写方式

2.2.1 基于if constexpr

if constexpr是一个编译期分支

优点:便于理解,

缺点:只能处理数值,同时小心引入运行期计算

复制代码
1 template <int x>
2 void fun(){
3     if constexpr(x>3) return x*2;
4     else return x*100;
5 }
6 
7 int main(){
8     fun<3>();
9 }
复制代码

2.2.2 基于特化

复制代码
 1 template <int x>
 2 struct Imp{
 3     constexpr static int value = x*2;
 4 };
 5 
 6 //特化
 7 template <>
 8 struct Imp<100>{
 9     constexpr static int value = 100-3;
10 };
11 
12 //发生分支的地方
13 constexpr int x = Imp<100>::value;
14 constexpr int y = Imp<97>::value;
15 
16 int main(){
17     std::cout << x << std::endl;
18     std::cout << y << std::endl;
19 }
复制代码

 

2.2.3 基于std::conditional

2.2.4 基于SFINAE

2.2.5 基于concept

2.2.6 基于三元运算符

2.3 循环代码的编写方式

复制代码
 1 template <int x>
 2 constexpr auto fun = (x % 2)+fun<x/2>;
 3 
 4 template <>
 5 constexpr auto fun<0> = 0;
 6 
 7 constexpr auto x = fun<99>;
 8 int main(){
 9     std::cout << x << std::endl;
10 }
复制代码

使用递归实现循环

任何一种分支代码的编写方式都对应相应的循环代码编写方式

三.减少实例化的技巧

为什么要减少实例化:提升编译速度,减少编译所需内存

相关技巧:

(1)提取重复逻辑以减少实力个数

(2)conditional使用时避免实例化

(3)使用std::conjunction/std::disjunction引入短路逻辑

其他技巧:减少分摊复杂度的数组元素访问操作

本文作者:OhOfCourse

本文链接:https://www.cnblogs.com/OhOfCourse/p/17173306.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   啊原来是这样呀  阅读(15)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起