| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> C++知识库 -> ”更高级的宏“模板到底是怎么实例化的? -> 正文阅读 |
|
[C++知识库]”更高级的宏“模板到底是怎么实例化的? |
文章目录
从预编译的角度对比宏定义和模板来测测宏定义大家都知道,宏定义仅仅只作用于文本的替换,在预编译的时候,把用到宏定义的部分替换为真正的文本而已,缺点就是不会做类型检查,只要语法能过编译就行。 我们定义一个宏来求两者之间的最大值,为了防止预编译的代码太过冗长不易看懂,没有用 代码如下:
经过
观察以上代码,我们发现,确实是直接的文本替换,前面的宏定义代码都不见了,只有,传入的替换文本了。 宏定义的害处
很明显,这个代码是可以过编译的,但我们肯定不想直接的如下的方式进行字符串的比较,这样的比较毫无意义,只不过是比较的地址而已。
故宏定义的最大危害,就是没法对类型进行检查!这就导致无法灵活的进行优化和调整一些直接文本替换带来的副作用。 模板是否会进行预处理操作?
我们发现模板并不会在预处理时被展开,它甚至不会和预处理的调用部分形成任何联系! 看来模板的展开处理过程是发生在后续的编译过程中,由于本人不清楚如何反汇编和反编译过程,故没有亲身实践。 但从我的日常使用体验和大佬们总结的经验看来,模板也和宏定义的展开类似,就是简单的文本替换,但可以利用编译时期的语法检查和类型判断(type_traits技术),所以能够对不同情况的展开进行不同的处理。 比如上面的代码利用偏特化进行优化:
善用编译期的模板为什么大多数模板库声明和定义都放在一起?声明和定义分开处理的原因我们清楚,声明和定义中,声明可以有无数份,但定义在一个项目里只能存在一份!所以我们在多文件项目的过程中,需要 话说回来,那为什么一般不会去直接把定义和声明写在一起呢? 很明显,定义和声明分开,无论我们怎么 为什么模板要把声明和定义写在一起?那既然如此,为什么写模板的时候声明和定义写在一个文件里面呢??? 我们前面已经清楚了,预编译命令
不出我所料,很快就报错,内容如下:
就是链接时找不到对应的函数定义,原因是模板只会在调用的时候实例化展开代码,如果
因为对应的.cpp文件里面,不会有任何的变更,也就是不会有对应的定义产生。 所以想要把声明和定义分文件且实现模板的实例化展开,几乎是不可能的(我目前不清楚有哪种方式可以(似乎在末尾再include定义的文件就可以但。。和直接include没区别)) 所以在写模板的时候,我们需要让使用到它的人(include调用者)把声明和定义一块给它,而防止找不到实例化展开的定义。 如何防止模板类的重复定义?以上描述了,为什么模板声明和定义需要写在同一个文件里,但问题又出现了,如何预防一个项目中产生多个定义呢? 简单预防: 通过预处理的宏定义控制导入导出的代码,但这样只能够保证一个 如下代码,我写了一个ttt.h文件,导出一个 print 函数的声明和定义(直接定义就包含声明)。
运行main函数时,很快就发生了重复定义的报错! 因为我们在test.cpp文件里面也 但我们又发现我们导入多次
好家伙,<bits/c++config.h> 是两千多行的宏定义!
以我目前的水平,看标准库就等于是看天书。。。 大概这就是C++劝退的原因之一吧,模板库为了防止重复定义,使得可读性变得极差,反正我是完全看不懂。。。 相对而言,Java的源代码直接就能简单上手看懂,而且比读文档还清晰,只能说C++的痛。。。 一些简单且常用的模板技术template + 函数声明将模板提前实例化一份由于我们template定义后,只有调用它的时候,才会实例化展开一份代码,但我们也能让编译器先为我们实例化一份代码,这个我也是最近才清楚有这个用法,以前从碰到过。
type_traits(类型萃取技术)type_traits是编译期就去确定具体的类型,而如何确定的呢,这个只需要用到模板的特化展开进行特定的标记即可。 比如写一个无符号整型的编译期类型判断工具可以像下面这样写: 原理就是利用的模板的实例化展开,再加上特定的偏特化,来对类内变量的值进行一个区分,便可实现类型的判断了。 type_traits + static_assert()的运用
assert和static_assert的对比共同点: 都是用于断言,满足条件则正常运行,否则抛出错误信息。 不同点: assert是在运行时且为DEBUG模式,出错后调用函数来进行报错退出处理。 static_assert()则是在程序编译时,在编译时进行判断,再抛出相应信息。 type_tarits的运用
通过type_trait可以实现只接受float类型和int类型。 |
|
C++知识库 最新文章 |
【C++】友元、嵌套类、异常、RTTI、类型转换 |
通讯录的思路与实现(C语言) |
C++PrimerPlus 第七章 函数-C++的编程模块( |
Problem C: 算法9-9~9-12:平衡二叉树的基本 |
MSVC C++ UTF-8编程 |
C++进阶 多态原理 |
简单string类c++实现 |
我的年度总结 |
【C语言】以深厚地基筑伟岸高楼-基础篇(六 |
c语言常见错误合集 |
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/24 5:28:43- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |