当前位置: 首页 > wzjs >正文

北京做erp报价的网站山东联通网站备案

北京做erp报价的网站,山东联通网站备案,wordpress生成手机端,中通建设计院网站1.模版编译原理 当我们在代码中使用了一个模板,触发了一个实例化过程时,编译器就会用模板的实参(Arguments)去替换(Substitute)模板的形参(Parameters),生成对应的代码。…

1.模版编译原理

当我们在代码中使用了一个模板,触发了一个实例化过程时,编译器就会用模板的实参(Arguments)去替换(Substitute)模板的形参(Parameters),生成对应的代码。同时,编译器会根据一定规则选择一个位置,将生成的代码插入到这个位置中,这个位置被称为 POI(point of instantiation)。由于要做替换才能生成具体的代码,因此 C++ 要求模板的定义对它的 POI 一定要是可见的。换句话说,在同一个翻译单元(Translation Unit)中,编译器一定要能看到模板的定义,才能对其进行替换,完成实例化。

2.包含模型

因此最常见的做法是,我们会将模板定义在头文件中,然后再源文件中 #include 头文件来获取该模板的定义。这就是模板编程中的包含模型(Inclusion Model)。

所以我们一般情况下,对于模版会把定义放在头文件中。但是这样操作会带来缺点。这个也对应着显示实例化的优点。

现在的一些 C++ 库,整个项目中就只有头文件,没有源文件,库的逻辑全部由模板实现在头文件中。而且这种做法似乎越来越流行,在 GitHub 和 boost 中能看到很多很多。我想原因一个是 C++ 缺乏一个官方的 package manager,这样发布的软件包更易使用(include就行了);另一个就是模板实例化的这种要求,使得包含模型成为泛型编程中组织代码最容易的方式。

但包含模型也有自身的问题。在一个翻译单元(Translation Unit)中,同一个模板实例只会被实例化一次。也就是对同一个模板传入相同的实参,编译器会先检查是否已实例化过,如果是则使用之前实例化的结果。但在不同的翻译单元中,相同实参的模板会被实例化多次,从而产生多个相同的类型、函数和变量

这带来两个问题:

2.1 链接时的重定义问题

如果不加以处理,这些相同的实体会被链接器认为是重定义的符号,这违反了ODR(One Definition Rule)。对这个问题的主流解决方案是为模板实例化生成的实体添加特殊标记,链接器在链接时对有标记的符号做特殊处理。例如在 GNU 体系下,模板实例化生成的符号都被标记为弱符号(Weak Symbol)。不需要我们参与,连接器已经为我们解决了这个问题。

对于普通的函数和类,连接器是不会处理的。会报重定义的错误。

同时这个因为每一个编译单元都有实例化,会带来代码膨胀。

2.2 编译时长的问题

同一个模板传入相同实参在不同的编译单元下被实例化了多次,这是不必要的,浪费了编译的时间。

3.分离模型

就是将声明放在头文件,实现放在.cpp中,并对其进行显示实例化,为什么要进行显示实例化,我在后面会详细的介绍。

显示实例化有如下的优点:

1. 降低编译器构建的时间

2.降低代码膨胀

3.针对发布lib,可以隐藏头文件

当然缺点也很明显,你要用到哪个模版类型,你提前事先都得很清楚,并且随着代码的累加,你都要动态的维护。

4.验证前面说的结论

1.如果在翻译单元的编译期间,能够看到模版的定义,就会在当前单元进行实例化。

也就是这个是一个多余的动作,就是能看见就顺便实例化了,调用函数正常。

2.如果在当前翻译单元看不到模版的定义,则只会调用这个函数,也就是认为声明在这个.h文件中,定义不在,链接的时候再去找。

3.正常的编译期就会生成对成员函数的调用,只是能看到模版的定义时,在本翻译单元的时候,才会进行实例化。如果在本翻译单元没有定义,则会在链接阶段再去找定义。

4.只要是实例化一定是在编译阶段,只是在你这个单元是否可见。

以上说的这几点,主要是针对包含模型和分离模型的对比来说的。

下面我们看下具体的例子。

我们先来解释第一句话:

//1.如果在翻译单元的编译期间,能够看到模版的定义,就会在当前单元进行实例化。
//也就是这个是一个多余的动作,就是能看见就顺便实例化了,调用函数正常。
//我们定义写一个main.cpp,再写一个function_template.h,然后在function_template.h中写一个实现的函数模版
// main.cpp
#include <iostream>
//#include "zhang.h"
#include "function_template.h"
int main() {int aa = 12;//Zhang temp;int num = system_latency_get_hardware_time(aa);std::cout<<num<<std::endl;return 0;
}
//function_template.h
template <typename Message>
int system_latency_get_hardware_time(const Message& message) {int a = 16;int b = 17;return a+b;
}
// 编译指令如下:
g++ -std=c++17 main.cpp   -o main
// 编译通过,执行./main
33
// 我们再来看下,分步操作会怎么样,我先生成汇编代码.
g++ -std=c++17 -S main.cpp -o main.s

查看对应的汇编代码,发现在汇编里已经出现了 system_latency_get_hardware_time

的定义

//我们修改 function_template.h的代码
// function_template.h
template <typename Message>
int system_latency_get_hardware_time(const Message& message);
// 然后再进行汇编操作
g++ -std=c++17 -S main.cpp -o main.s

这个时候我们汇编不会报错,正如我们第二点所说.

2.如果在当前翻译单元看不到模版的定义,则只会调用这个函数,也就是认为声明在这个.h文件中,定义不在,链接的时候再去找。

关于这个函数搜索只能找到这一条数据。

而我们现在继续向下,链接会怎么样,应该会报链接错误,我们试试.

// 为了少打几个指令,直接进行一步
g++ -std=c++17 main.cpp   -o main
这个时候,在链接的时候,就会报错g++ -std=c++17 main.cpp   -o main
/tmp/ccgzva3Q.o: In function `main':
main.cpp:(.text+0x26): undefined reference to `int system_latency_get_hardware_time<int>(int const&)'
collect2: error: ld returned 1 exit status

这个错误,我们是可以接受的,因为我们确实没有定义.

那我们想把,模版的定义,放到.cpp中可以吗?

// 在刚才的基础上
// function_template.h
template <typename Message>
int system_latency_get_hardware_time(const Message& message);
// add function_template.cpp
#include "function_template.h"
template <typename Message>
int system_latency_get_hardware_time(const Message& message) {int a = 16;int b = 17;return a+b;
}
// 然后我在编译代码的时候,链接下function_template.cpp是不是就可以了呢?
// g++ -std=c++17 main.cpp  function_template.cpp -o main
/tmp/ccsWDsr1.o: In function `main':
main.cpp:(.text+0x26): undefined reference to `int system_latency_get_hardware_time<int>(int const&)'
collect2: error: ld returned 1 exit status

我们发现还是不行,这个其实很好理解,因为在 另外一个编译单元(一个cpp文件就是一个编译单元), function_template.cpp中,这个不会生成这个函数,因为模版没有被实例话,那么方法来了,我们来进行下显示的实例话。

// function_template.cpp
#include "function_template.h"
template <typename Message>
int system_latency_get_hardware_time(const Message& message) {int a = 16;int b = 17;return a+b;
}
// 显示实例话  这个必须放在定义的后面,在.h和.cpp里无所谓.
template int system_latency_get_hardware_time<int> (const int&);

再进行编译,g++ -std=c++17 main.cpp function_template.cpp -o main

我们发现可以编译通过了,说明在 function_template.cpp中,会生成这个函数,那么我们没有给函数体,函数体是谁呢?很显然是是使用 primary template的函数体,因为执行程序的输出是 33.

到现在为止,1,2,3,4 点我都解释清楚了。

这里要主要一个细节,就是类模版的全特化和函数模版的全特化还有些不同,类模版如果全特化以后,还需要进行实例化才能生成代码,但是函数模版的全特化后,不需要实例化了,直接可以生成代码,具体可以参考我的下一篇博文 深入浅出之STL源码分析5_模版实例化与全特化-CSDN博客

http://www.dtcms.com/wzjs/566401.html

相关文章:

  • wordpress文章打不开网站改版优化
  • 免费素材网站图库阜新门户网站建设
  • 默认网站停止手机在线app下载
  • 南京网站a建设云世家桂阳网页定制
  • 公司网站建设会计你分录深圳市官网网站建设报价
  • 找人做海报在什么网站找汕尾东莞网站建设
  • 怎么样增加网站权重wordpress实现付费阅读
  • 手机像素网站河北区网站建设
  • 嘉兴制作手机网站wordpress用于商业
  • 站内搜索本网站怎么做哪位大神推荐一下好网站
  • 网站建设的模块电子政务与网站建设 总结
  • 公司网站设计案例定制网站制作服务商
  • 做兼职网站赚钱吗杭州网站提升排名
  • 导视标识设计做搜狗网站优化首页软
  • seo推广必须要做的9种方法上海seo推广
  • 网站建设 质量标准沙井做网站公司
  • 网站建设制作收费仿新浪首页网站模板
  • 培训网站哪个最好的广州网站设计易企建站
  • gta5房子网站建设中前端编程工程师培训
  • vps如何做网站优化师和运营区别
  • 专业app怎么制作网站吗wordpress 本地调试
  • 货代找客户的网站黄山公司做网站
  • 哪做网站好网页游戏传奇盛世开服表
  • 课程网站开发网站建设与管理资料下载
  • 怎么做企业招聘网站城北区建设局网站
  • 建立网站的内容规划广告点击网站源码
  • 免费网站制作软件有哪些seo关键词排名系统
  • 网站运营软件网站开发怎么根据设计稿的尺寸算图片高度
  • 东莞网站设计图书馆网站建设研究
  • 手机网站设计公司皆选亿企邦php大型网站开发书籍