模板元编程简介

从引入 template 关键字开始,C++里就出现了泛型编程,而又泛型编程衍生出的模板元编程(template meta_programming,简称“元编程”)则是众多编程范式中最复杂、最强大和最具有权威的一种。所谓“元编程”——metaprogramming,有着完全不同于普通程序的许多特点,是一种全新的编程体验。下面将介绍模板元编程的一些基础概念,它们是现代C++和boost程序库组件的基础。

1. 概述

元编程(meta-programming)也被称为“超程序”,“超编程”或“产生式编程”,这样说法一定程度上反映了其本质——它是一种位于普通程序之上、超越普通程序的程序,可以操纵、产生程序的程序。模板元编程本质上是泛型编程的一个子集,从广义上来说,所有使用template 的泛型代码都可以称作元程序——因为泛型编程代码并不是真正可编译执行的代码,它们只是定义了代码的产生规则,是用来生成代码的“模板”。然而模板元编程又不完全等同于泛型编程,它是一种“函数式编程”,是图灵完备的,可以“计算”任何东西。
模板元编程的允许是在编译期,它把编译器变成了元程序的解释器。

2. 语法元素

模板元编程产生的元程序是在编译期执行的程序,操作对象也不是普通的变量,因此不能使用运行时的C++ 关键字(if、else、for),可以的语法元素相当有限,最常用的包括:

  • enum、static 用来定义编译期的变量
  • typedef、using,最重要的元编程关键字,用于定义元数据
  • template,模板元编程的“起点”,主要用于定义元函数
  • “::”,域运算符,用于解析类型作用域获取计算结果(元数据)

3. 元数据

元编程可操作的数据就称为“元数据”(meta date),也就是C++ 编译器在编译期可操作的数据,它是模板元编程的基础。元数据都是不可变的,不能够就地修改,最常见的元数据是整数和C++ 类型(type)。这些元数据不是运行时的普通变量,而是如 int、double、class(非模板类)这样的抽象数据类型。要是对元数据再细分归类,则它又可分为:

  • 整数元数据
  • 值型元数据(int、double等POD值类型)
  • 函数元数据(函数类型)
  • 类元数据(class、struct等用户自定义类型)

对于下面所提到的‘元数据“,特征非整数类型的元数据。
使用tyoedef 关键字可以任意定义(声明)元数据,很像运行时的变量定义,如:

typedef int mtes_data1;   //元数据meta_data1, 值为 int
typedef std::vector<float> meta_data2; //元数据meta_data2,值为vector<float>使用using 也可以达到同样的效果
using meta_data1 = int;
using meta_data2 = std:;vector<float>;

4. 元函数

元函数(meta function)是模板元编程中用于操作处理元数据的”构件“,可以在编译期被”调用“,因为其功能和形式类似运行时的函数而得名,是元编程里的核心概念。它实际上是一个类或者模板类,通常形式为:

template<typename arg1, typename arg2, ...>  //元函数参数列表
struct meta_function  //元函数名
{typedef sone-define type;  //元函数返回元数据//using type = some-define; static int const val = some-int;  //元函数返回的整数
};//结束

编写元函数就像是编写一个普通的运行是函数,但形式上却是一个模板类:

  • 函数参数列表的园括号”()“ 变成了模板列表的尖括号”<>“
  • 函数的形参变成了模板参数(即元数据),并且要使用关键字 typedef 修饰
  • 因为不能使用运行时关键字,所以元函数不能像其他普通函数那样使用return 返回计算结果,而是需要在内部使用typedef / using 定义一个名为 type 的类型(元数据)或者名为val 的值作为返回
  • 最后以分号结束,因为它本质上是一个类

元函数也可以没有返回值(即不定义内部类型type),也可以有重载(模板特例/偏特化),也可以有缺省参数,也可以分为无参、单参、多参、可变参等类别。但元函数没有普通函数参数传值、传引用的区别,也没有函数指针的概念。如果有必要,元函数可以使用 typedef / using 关键字 “返回” 任意多个返回值,并且这些没有顺序关系,能够用 ”::“ 来任意获取。为表述方便,下面将只返回 ::type 的元函数称为标准元函数,而返回多个元数据的元函数称为非标准元函数。
下面给一段值元函数的代码:

template<int N, int M>  //两个元数据
struct meta_func
{static const int val = N + M; //编译期计算整数之和
};cout << meta_func<10, 10>::val << endl; //计算结果 20

这里需要主要的是meta_func 的执行过程,它的计算在编译期的时候就已经完成了(即模板实例化),meta_func::val 实际上是一个编译期常量,程序运行时不会有任何计算动作而是直接使用结果。如果这是一个大型的元函数,那么在编译期节约的计算量就会相当可观,可以显著提高程序运行的效率。
由于元函数的计算发生在编译期,所以下列代码不能成立:(不能使用运行时的变量)
在这里插入图片描述
下面示范了另一个元函数,它返回元函数参数列表中的第一个元数据:

template<typename T1, typename T2>  //两个形参
struct select1st
{typedef T1 type;  //返回T1,等价于using type = T1
};

5. 元函数转发

元函数转发是模板元编程中一个经常用到的惯用法,相当于运行时的函数转发调用,但在模板元编程中则要用 public 继承实现,模板参数传递给父类完成元函数的 ”调用“,这样的子类会自动获得父类的::type 定义,同时也完成了元函数的返回。例如,下面代码把元函数数据调换位置后,转发给之前定义的元函数 select1st ,相当于select2nd 的功能:

template<typename T1, typename T2>
struct forword: select1st:  //元函数转发,默认是public继承select1st<T2, T1>  //参数位置变动
{};template<typename T1, typename T2>
struct forward  //不用转发
{typedef typename select1st<T2, T1>::type type; //调用元函数计算
};

易知,元函数转发因为使用了类继承所以更加简洁

6. 工具宏

模板元编程是一种全新的C++ 编程范式,但仍然使用原有的语法,通篇的 typedef / using 、 template 关键字使元程序不易理解,所有完美可以定义一些工具宏,均以“mp_”开头(或者用增加习惯的方法定义),这样能够便于我们理解。

#define mp_arglist template //元函数参数列表
#define mp_arg    typename  //元函数参数声明
#define mp_function struct //元函数定义
#define mp_data  typedef //元数据定义#define mp_return(T) mp_data T type  //元函数返回
//using type = T
#define mp_exec(Func)  Func::type   //获取元函数返回结果
#define eval(Func)   Func::value   //获取元函数返回值

这些分别把 template 、typename、struct 和 typedef 这四个模板元编程中最常用的关键字进行了重命名。

  • mp_arglist 表示元函数的参数列表开始
  • mp_arg 表示元函数的参数
  • mp_function 表示定义一个元函数
  • mp_data 表示定义一个元数据
  • mp_return / mp_eval / mp_exec 定义了元编程中约定返回值用法,较原写法更清楚
mp_data int meta_data1;   //元数据meta_data1,值为intmp_arglist<mp_arg T1, mp_arg T2>    //元函数的参数是T1、T2
mp_function select1st  //元函数select1st
{mp_return(T1);  //返回T1  -> type
}

很明显,使用工具宏使元程序看起来更加清楚,易于区分。但是由于宏预处理机制自身的“缺陷”,后三个工具宏的作用有限,它们只能处理简单的参数,如果带有 “,”,那么模板类就会失效,但Boost 库里面的 BOOST_IDENTITY_TYPE 来解决。

7. 应用示例

下面通过两个例子来示范元编程的基本使用:

  • 编译期比较大小
mp_arglist<int L, int R>
mp_function static_min  //元函数 static_min
{static const int value = (L < R) ? L : R;
};assert((static_min<10, 20>::value == 10)); //编译期比较
  • demo_func 输入元数据 T 是指针类型返回const T,否则 const T*
mp_arglist<mp_arg T>   //单参元函数
mp_function demo_func
{mp_return(const T*);   //通常情况返回const T*
};mp_arglist<mp_arg T>
mp_function demo_func<T*>   //对T*情况进行模板实例化
{mp_return(const T);
};//这里用is_same元函数进行验证 #include<boost/type_traits/is_same>
assert((is_same<mp_exec(demo_func<int>), const int*>::value));
assert((is_same<mp_exec(demo_func<int*>), const int>::value));
//这里的 assert 必须用两对括号来包围断言

8. 总结

我们介绍了模板元编程的基础知识,包括元编程 / 元程序 / 元数据 和 元函数转发等概念。

  • 元编程是一种超越普通程序的程序,在C++中元编程是使用模板技术实现的,所以它右被称为模板元编程。元程序可以由C++编译期解释执行,把部分计算量由运行时转移到编译时完成,提高程序运行效率,但元编程更大的用途是类型推导,操作C++类型体系。
  • 元数据是元编程的操作对象,可以是整数(含bool)或任意的C++类型
  • 元函数是元编程的核心,它表现为C++的一个模板类,我们必须使用元函数才能操作元数据。它以内部定义::type 或 ::value 返回计算结果,并可以使用public 继承的方式实现元函数转发

至此结束

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/603677.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Keil C51的编译器限制

编译器限制 Cx51 编译器体现了下面列出的一些已知限制。在大多数情况下&#xff0c;对 C 语言的组件没有限制;例如&#xff0c;您可以在 switch 块中指定无限数量的符号或 case 语句。如果有足够的地址空间&#xff0c;则可以定义数千个符号。 最多支持对任何标准数据类型的 …

二叉树的经典算法(算法村第八关青铜挑战)

二叉树里的双指针 所谓的双指针就是定义了两个变量&#xff0c;在二叉树中有需要至少定义两个变量才能解决问题。这两个指针可能针对一棵树&#xff0c;也可能针对两棵树&#xff0c;姑且也称之为“双指针”。这些问题一般与对称、反转和合并等类型题相关。 判断两棵树是否相…

Python:tqdm模块详解

tqdm 是一个用于在 Python 中显示进度条的模块&#xff0c;用于在循环或迭代过程中展示任务的进度。 1. 安装 首先&#xff0c;你可以通过 pip 安装 tqdm 模块&#xff1a; pip install tqdm2. 基本使用方法 在 Python 中使用 tqdm &#xff0c;只需将你的迭代对象传递给 tqd…

【Linux】之搭建 PostgreSQL 环境

前言 在 Linux 系统下安装 PostgreSQL&#xff0c;可以选择快捷方便的 Docker 安装&#xff0c;但正常的服务器都是直接原生安装的&#xff0c;所以&#xff0c;这里我将讲解如何正常安装 PostgreSQL 以及安装之后的一些配置。如果想了解 Docker 安装的话&#xff0c;可以查看我…

竞赛练一练 第27期:GESP和电子学会相关题目练习

GESP一级2023.03_小猫捉老鼠 1. 准备工作 (1)导入背景Room 2; (2)删除默认小猫角色,导入角色Mouse1、Cat 2。 2. 功能实现 (1)点击绿旗,老鼠出现在随机位置; (2)通过键盘的“↑”、“↓”、“←”、“→”键来控制小猫行走,每按一次,移动5步; (3)小猫在…

使用openCV进行图像处理

使用 openCV进行图像处理 使用 openCV进行图像处理&#xff0c;又名&#xff1a;学习计算机视觉理论&#xff0c;做 demo(第3 天&#xff09; 目录 2.1 图像模糊 2.1.1 均值滤波2.1.2 中值滤波2.1.3 高斯滤波2.1.4 案例实现 2.2 图像锐化 2.2.1 图像锐化简介2.2.2 案例实现 …

Spring依赖注入的魔法:深入DI的实现原理【beans 五】

欢迎来到我的博客&#xff0c;代码的世界里&#xff0c;每一行都是一个故事 Spring依赖注入的魔法&#xff1a;深入DI的实现原理【beans 五】 前言DI的基本概念基本概念&#xff1a;为什么使用依赖注入&#xff1a; 构造器注入构造器注入的基本概念&#xff1a;示例&#xff1a…

laravel-admin之 浏览器自动填充密码(如果需要渲染数据库密码的话,首先确认数据库密码是否可以逆向解密)

参考 https://blog.51cto.com/u_10401840/5180106 为什么浏览器端保存的密码一直自动写入到$form->password 解决办法 2、在页面进入的时候&#xff0c;默认表单的type值为text&#xff1b;推荐指数&#xff1a;2颗星 5、设置表单的readonly属性;推荐指数&#xff1a;4颗…

实习遇到问题备忘录

1.Hutool工具包的DB Hutool学习 —— 数据库 - db &#xff08;一&#xff09;Db简单操作 - 简书 (jianshu.com) 2.Consumer函数接口 Java 常用函数式接口之Consumer接口 - LeeHua - 博客园 (cnblogs.com) 3.sql高级用法merge into SQL高级知识——MERGE INTO - 知乎 (zhi…

Linux 上 Nginx 配置访问 web 服务器及配置 https 访问配置过程记录

目录 一、前言说明二、配置思路三、开始修改配置四、结尾 一、前言说明 最近自己搭建了个 Blog 网站&#xff0c;想把网站部署到服务器上面&#xff0c;本文记录一下搭建过程中 Nginx 配置请求转发的过程。 二、配置思路 web项目已经在服务器上面运行起来了&#xff0c;运行的端…

222.【2023年华为OD机试真题(C卷)】分配土地(扫描线算法-JavaPythonC++JS实现)

🚀点击这里可直接跳转到本专栏,可查阅顶置最新的华为OD机试宝典~ 本专栏所有题目均包含优质解题思路,高质量解题代码(Java&Python&C++&JS分别实现),详细代码讲解,助你深入学习,深度掌握! 文章目录 一. 题目-分配土地二.解题思路三.题解代码Python题解代码…

FineBI:简介

1 介绍 FineBI 是帆软软件有限公司推出的一款商业智能&#xff08;Business Intelligence&#xff09;产品。 FineBI 是定位于自助大数据分析的 BI 工具&#xff0c;能够帮助企业的业务人员和数据分析师&#xff0c;开展以问题导向的探索式分析。 2 现阶段数据分析弊端 现阶…

广义零样本学习综述的笔记

1 Title A Review of Generalized Zero-Shot Learning Methods&#xff08;Farhad Pourpanah; Moloud Abdar; Yuxuan Luo; Xinlei Zhou; Ran Wang; Chee Peng Lim&#xff09;【IEEE Transactions on Pattern Analysis and Machine Intelligence 2022】 2 conclusion Generali…

【DevOps-05】Integrate工具

一、简要说明 持续集成、持续部署的工具很多,其中Jenkins是一个开源的持续集成平台。 Jenkins涉及到将编写完毕的代码发布到测试环境和生产环境的任务,并且还涉及到了构建项目等任务。 Jenkins需要大量的插件保证工作,安装成本较高,下面会基于Docker搭建Jenkins。 二、Jenk…

HPM6750开发笔记《DMA接收和发送数据UART例程深度解析》

目录 概述&#xff1a; 端口设置&#xff1a; 代码分析&#xff1a; 运行现象&#xff1a; 概述&#xff1a; DMA&#xff08;Direct Memory Access&#xff09;是一种计算机系统中的数据传输技术&#xff0c;它允许数据在不经过中央处理器&#xff08;CPU&#xff09;的直…

Vue2:修改默认配置的方法

一、前情概要 之前我们说到&#xff0c;用vue-cli创建vue项目之后&#xff0c;项目结构大概是这样的。其中&#xff0c;标红部分的文件是非常重要的结构文件&#xff0c;不建议修改文件名。 但是&#xff0c;实际上了&#xff0c;vue是允许修改的。 准备配置文件&#xff1a;v…

软件测试|使用PyMySQL访问MySQL数据库的详细指南

简介 PyMySQL是Python中流行的MySQL数据库驱动程序&#xff0c;它提供了便捷的方法来连接、查询和更新MySQL数据库。本文将为您提供使用PyMySQL访问MySQL数据库的详细指南&#xff0c;包括安装PyMySQL、连接数据库、执行查询和更新操作等。 环境准备 在开始之前&#xff0c;…

编译原理笔记(三)

一、词法分析程序的设计 1、词法分析程序的输出 在识别出下一个单词同时验证其词法正确性之后&#xff0c;词法分析程序将结果以单词符号的形式发送至语法分析程序以回应其请求。 单词符号一般分下列5类&#xff1a; 关键字&#xff1a;如&#xff1a;begin、end、if、whil…

双变量probit模型

1. Probit模型 1.1 模型含义 假设个体只有两种选择&#xff0c;y1或y0。影响选择的变量都包括在向量x中。即线性概率模型为 y值服从两点分布 被认为是连接函数&#xff0c;函数选择具有一定的灵活性。如果为标准正态的累积分布函数&#xff0c;则模型成为Probit模型&#xff…

NACHI机器人模拟示教器如何切换中文

前言 现在开始学习机器人的编程语言&#xff0c;那么要学习会用首先得用模拟示教器来学习&#xff0c;但是全是英文确实比较难受一些些&#xff0c;没有中文来的直观。所以摸透一下如何给示教器更换语言。 具体步骤 步骤一&#xff1a;将中文的汉化包下载下来。具体的下载链…