【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 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步