C++模版完全解析
模版
模版在C++中是一个很重要的概练,生活中的模版也是随处可见,比如制造工程师会
哪一个模子去构造出一个一个的工件,C++程序员能够用模版去实例化y有相同操作
不同类型的函数或者数据结构。简单的理解模版就是为省去重复,同时又比C中的宏容易调试
因为C++编译器会做类型参数语法检查。
C中的模版模拟
想当年C++还没有出现模版的时候,C程序员可能为了写比较两个数的最大值写出如下几种类型
int max_int(int x,int y){return x>y?x:y}
int max_double(double x,double y){return x>y?x:y}
int max_string(string x,string y){return x>y?x:y}//C++中
这样的写法实在太繁杂,后来由发现用宏来写可能会舒服点儿,比如
//macro.cpp
#include <iostream>
using namespace std;
#define MAX(T) \
T max_##T(T x,T y)\
{\
return x>y?x:y;\
}\
MAX(int)
MAX(string)
MAX(double)
#define max(T) max_##T
int
main(int argc, char ** argv){
cout<<"int:"<<max(int) (2,3)<<endl;
cout<<"double:"<<max(double) (3.3,1.2)<<endl;
cout<<"string:"<<max(string) (string("welcome"),string("guiyang"))<<endl;
cout<<endl;
return 0 ;
}
这样看是比写三个方便了,在这个地方有几个东西需要说明
- 1.我们最终任然是写了三个函数,只不过是通过 预处理器 的方式来为我们创建了
因为宏只在预处理的时候有效 - 2.一旦预处理完成我们的宏就不见了不能在符号表找到,不能加-g调试
- 3.为了确定我们的函数生成在预处理阶段我们可以看一下预处理信息
# 2 "macro.cpp" 2
using namespace std;
int max_int(int x,int y){return x>y?x:y;}
string max_string(string x,string y){return x>y?x:y;}
double max_double(double x,double y){return x>y?x:y;}
int
main(int argc, char ** argv){
cout<<"int:"<<max_int (2,3)<<endl;
cout<<"double:"<<max_double (3.3,1.2)<<endl;
cout<<"string:"<<max_string (string("welcome"),string("guiyang"))<<endl;
cout<<endl;
return 0 ;
}
[lmg@localhost cpp]$
C++中的模版
C++中的模版也采用了相似的思想,不过将其变为了函数模版
即定义出一个通用的函数,用类型参数形参表示具体的函数模版的类型
- 语法:
template <[typename|class] argsname1,[typename|class] argsname1,...> argsname funcname(argsname1 x,argsname2 y,...) - 调用:
funcname<argsname1 ,argsname2,..>(x,y,...) - 注意:
- 1.模版形参表和模版实参表要对应,可以有多个
- 2.模版的声明和使用一般通常的编写手法是放在一个头文件中,需要用到的包含文件即可
- 3.通常我们写C文件的时候会将声明放在头文件中,而将定义实现放在.c文件中,这是因为
我们的C/C++通常的处理是声明可以重复但是定义是不能重复的。 - 4.类型形参表是由调用的类型实参进行实例化,此过程完成在编译阶段,和上面的C实现的区别主要是
C实现发生在预处理阶段,但是最终都会生成多份儿符号儿表
代码实现
#include <iostream>
template <typename T> //定义模版名称
T max(T x, T y){
return x>y?x:y;
}
int
main(int argc, char ** argv){
std::cout<<"int:"<<max<int>(3,2)<<std::endl;
std::cout<<"doule:"<<max<double>(2.4,3.4)<<std::endl;
std::cout<<"string:"<<max<std::string>("welcome","beijing")<<std::endl;
}
为了进一步分析模版实现的特点我们观察如下两个方面
- 预处理模版的代码
# 2 "template.cpp" 2
template <typename T>
T max(T x, T y){
return x>y?x:y;
}
int
main(int argc, char ** argv){
std::cout<<"int:"<<max<int>(3,2)<<std::endl;
std::cout<<"doule:"<<max<double>(2.4,3.4)<<std::endl;
std::cout<<"string:"<<max<std::string>("welcome","beijing")<<std::endl;
}
从预处理结果可以看出预处理结果中模版代码并没有改变
- 用nm命令查看连接结果符合表
0000000000601248 d _DYNAMIC
0000000000601410 d _GLOBAL_OFFSET_TABLE_
0000000000400dd7 t _GLOBAL__I_main
0000000000400fa8 R _IO_stdin_used
w _Jv_RegisterClasses
U _Unwind_Resume@@GCC_3.0
0000000000400e3c W _Z3maxISsET_S0_S0_
0000000000400e08 W _Z3maxIdET_S0_S0_
0000000000400dec W _Z3maxIiET_S0_S0_
0000000000400d97 t _Z41__static_initialization_and_destruction_0ii
U _ZNKSs7compareERKSs@@GLIBCXX_3.4
U _ZNSaIcEC1Ev@@GLIBCXX_3.4
U _ZNSaIcED1Ev@@GLIBCXX_3.4
U _ZNSolsEPFRSoS_E@@GLIBCXX_3.4
U _ZNSolsEd@@GLIBCXX_3.4
U _ZNSolsEi@@GLIBCXX_3.4
U _ZNSsC1EPKcRKSaIcE@@GLIBCXX_3.4
U _ZNSsC1ERKSs@@GLIBCXX_3.4
U _ZNSsD1Ev@@GLIBCXX_3.4
U _ZNSt8ios_base4InitC1Ev@@GLIBCXX_3.4
U _ZNSt8ios_base4InitD1Ev@@GLIBCXX_3.4
00000000006014c0 B _ZSt4cout@@GLIBCXX_3.4
U _ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_@@GLIBCXX_3.4
00000000006015e0 b _ZStL8__ioinit
0000000000400e90 W _ZStgtIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_
U _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@@GLIBCXX_3.4
U _ZStlsIcSt11char_traitsIcESaIcEERSt13basic_ostreamIT_T0_ES7_RKSbIS4_S5_T1_E@@GLIBCXX_3.4
0000000000400fe0 r _ZZL18__gthread_active_pvE20__gthread_active_ptr
0000000000601228 d __CTOR_END__
0000000000601218 d __CTOR_LIST__
0000000000601238 D __DTOR_END__
0000000000601230 d __DTOR_LIST__
00000000004011d8 r __FRAME_END__
0000000000601240 d __JCR_END__
0000000000601240 d __JCR_LIST__
00000000006014bc A __bss_start
U __cxa_atexit@@GLIBC_2.2.5
00000000006014b8 D __data_start
0000000000400f60 t __do_global_ctors_aux
0000000000400b20 t __do_global_dtors_aux
0000000000400fb0 R __dso_handle
w __gmon_start__
U __gxx_personality_v0@@CXXABI_1.3
0000000000601213 d __init_array_end
0000000000601213 d __init_array_start
0000000000400ec0 T __libc_csu_fini
0000000000400ed0 T __libc_csu_init
U __libc_start_main@@GLIBC_2.2.5
00000000006014bc A _edata
00000000006015e8 A _end
0000000000400f98 T _fini
0000000000400988 T _init
0000000000400ad0 T _start
0000000000400afc t call_gmon_start
00000000006015d0 b completed.6349
00000000006014b8 W data_start
00000000006015d8 b dtor_idx.6351
0000000000400b90 t frame_dummy
0000000000400bb4 T main
w pthread_cancel
从下面的符合表
0000000000400e3c W _Z3maxISsET_S0_S0_
0000000000400e08 W _Z3maxIdET_S0_S0_
0000000000400dec W _Z3maxIiET_S0_S0_
可以看出生成了三分儿模版函数实例
必知知识点
为了便于理解模版我觉得如下概练需要进一步强度
- 1、宏替换发生在预处理阶段 -E参数可以看到处理结果
- 2、模版函数实例化函数模版发生在编译阶段,可以nm命令通过分析二进制文件符合表发现
- 3、函数模版和模版函数的形参表的顺序必须一致,因为简单理解其实现的是对应替换的功能,再加一点儿编译器做的类型检查
- 4、模版形参必须是能支持函数模版的操作,比如一个用“>”符合的比较函数,其模版类型T必须能支持“>”符号或者重载了该运算符
- 5、模版声明定义一般直接放入头文件中,和通常的声明放在头文件实现放在.C|.CPP文件略有不同
C++模版完全解析的更多相关文章
- thinkphp禁止模版标签解析
场景: 页面中某些样式或者js中含有tp定义的模版标签,如果被tp当成模版标签解析,就会解析异常. tp中提供了<literal></literal>标签用于禁止标签内部的代码 ...
- dedecms中的模版不解析dede:global
先安装dedecms,配置好各项内容,栏目,网站内容等. 最近在使用dedecms做后台开发一个手机网站的项目,前端设计都是用html5来设计.很多地方都需要使用dede:global标签来调取全局变 ...
- Nodejs学习笔记(五)--- Express安装入门与模版引擎ejs
目录 前言 Express简介和安装 运行第一个基于express框架的Web 模版引擎 ejs express项目结构 express项目分析 app.set(name,value) app.use ...
- 由“Jasperrpeorts 4.1.2升级到5.1.2对flex项目的解析”到AS3 带命名空间的XML的操作
原文同步至:http://www.waylau.com/from-jasperrpeorts-4-1-2-upgraded-to-5-1-2-parsing-of-flex-projects-to-t ...
- Express安装入门与模版引擎ejs
Express安装入门与模版引擎ejs 目录 前言 Express简介和安装 运行第一个基于express框架的Web 模版引擎 ejs express项目结构 express项目分析 app.set ...
- Spring Boot 集成 thymeleaf 模版引擎
Spring Boot 建议使用 HTML 来完成动态页面.Spring Boot 提供了大量的模版引擎,包括 Thymeleaf.FreeMarker.Velocity等. Spring Boot ...
- Nodejs学习笔记(五)—Express安装入门与模版引擎ejs
前言 前面也学习了一些Node.js的基本入门知道,现在开始进入Web开发的部分: Node.js提供了http模块,这个模块中提供了一些底层接口,可以直接使用,但是直接开发网站那还是太累了,所以ht ...
- 服务端模版注入漏洞检测payload整理
服务端模版注入漏洞产生的根源是将用户输入的数据被模版引擎解析渲染可能导致代码执行漏洞 下表涵盖了java,php,python,javascript语言中可能使用到的模版引擎,如果网站存在服务端模版注 ...
- 用RegularJS开发小程序 — mpregular解析
本文来自网易云社区. Mpregular 是基于 RegularJS(简称 Regular) 的小程序开发框架.开发者可以将直接用 RegularJS 开发小程序,或者将现有的 RegularJS 应 ...
随机推荐
- eclipse svn修改用户名密码
1,svn客户端删除 2,eclipse 补充,上图为网友资料,但实际操作过程中,发现eclipse中svn为svnkit,但相应目录下无.keyring文件,最后按步骤2删除auth下所有文件,再次 ...
- svn问题:在eclipse里面使用SVN,怎么实现版本回滚呢?
共有4个答案 我要回答» JustForFly 回答于 2012-04-27 10:20 举报 想回到SVN服务器端的最新版本就使用 team->还原.. 想回到SVN服务器端的其它版本使用 ...
- codeforces 688E E. The Values You Can Make(dp)
题目链接: E. The Values You Can Make time limit per test 2 seconds memory limit per test 256 megabytes i ...
- P4284 [SHOI2014]概率充电器 dp
这个题题干说的不清楚,一开始我以为只能是旁边紧挨着的传火,导致我一开始根本不知道哪错了.后来,我想到树形dp,但是需要正反考虑,()既要考虑父亲,又要考虑儿子),互相都有影响,所以没太想出来.后来知道 ...
- Windows下手动安装redis服务
1.Redis本身不支持windows,但是有另外的团队在维护着一个windows下的版本 2.下载地址: https://github.com/MSOpenTech/redis 2.8的版本在源 ...
- Bootstrap中的各种下拉菜单
@*基本下拉菜单与按钮下拉菜单的样式完全一致.不过,基本的下拉菜单使用<div class="dropdown">包裹,所有要换行.而按钮式下拉菜单<div cl ...
- Pascal输出星星
program Project2; {$APPTYPE CONSOLE} uses SysUtils; var i,j:integer; begin { TODO -oUser -cConsole M ...
- HDU3092:Least common multiple(素数筛选+完全背包)
题意 给出\(n\)和\(m\),将\(n\)拆成任意个数,求它们的最大的\(lcm\) 分析 1.可以证明\(n=p1^{s1}*p2^{s2}*...*pn^{sn}\)时\(lcm\)最大(其中 ...
- JavaScript实现对象的深度克隆及typeof和instanceof【简洁】【分享】
JavaScript实现对象的深度克隆 代码实现如下: <!DOCTYPE html> <html lang="en"> <head> < ...
- (11)用css设计电子相册 {上}
本篇学习资料讲解: 通过css对电子相册进行排版 和 侧面强调“盒子模型.标准流.浮动和定位”的重要性. 先来看看"双向联动模式"的电子相册图: {鼠标指针经过某张图片 ...