模版

模版在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++模版完全解析的更多相关文章

  1. thinkphp禁止模版标签解析

    场景: 页面中某些样式或者js中含有tp定义的模版标签,如果被tp当成模版标签解析,就会解析异常. tp中提供了<literal></literal>标签用于禁止标签内部的代码 ...

  2. dedecms中的模版不解析dede:global

    先安装dedecms,配置好各项内容,栏目,网站内容等. 最近在使用dedecms做后台开发一个手机网站的项目,前端设计都是用html5来设计.很多地方都需要使用dede:global标签来调取全局变 ...

  3. Nodejs学习笔记(五)--- Express安装入门与模版引擎ejs

    目录 前言 Express简介和安装 运行第一个基于express框架的Web 模版引擎 ejs express项目结构 express项目分析 app.set(name,value) app.use ...

  4. 由“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 ...

  5. Express安装入门与模版引擎ejs

    Express安装入门与模版引擎ejs 目录 前言 Express简介和安装 运行第一个基于express框架的Web 模版引擎 ejs express项目结构 express项目分析 app.set ...

  6. Spring Boot 集成 thymeleaf 模版引擎

    Spring Boot 建议使用 HTML 来完成动态页面.Spring Boot 提供了大量的模版引擎,包括 Thymeleaf.FreeMarker.Velocity等. Spring Boot ...

  7. Nodejs学习笔记(五)—Express安装入门与模版引擎ejs

    前言 前面也学习了一些Node.js的基本入门知道,现在开始进入Web开发的部分: Node.js提供了http模块,这个模块中提供了一些底层接口,可以直接使用,但是直接开发网站那还是太累了,所以ht ...

  8. 服务端模版注入漏洞检测payload整理

    服务端模版注入漏洞产生的根源是将用户输入的数据被模版引擎解析渲染可能导致代码执行漏洞 下表涵盖了java,php,python,javascript语言中可能使用到的模版引擎,如果网站存在服务端模版注 ...

  9. 用RegularJS开发小程序 — mpregular解析

    本文来自网易云社区. Mpregular 是基于 RegularJS(简称 Regular) 的小程序开发框架.开发者可以将直接用 RegularJS 开发小程序,或者将现有的 RegularJS 应 ...

随机推荐

  1. js连等运算

    1.var a = b = 20; 连等的第二个变量属于全局变量2.a.x = a = {n:2}; 连等是从右往左执行的3.a.x = a = {n:2}; js语句执行前会保存之前的索引

  2. hash与map的区别联系应用

    一,hashtable原理: 哈希表又名散列表,其主要目的是用于解决数据的快速定位问题.考虑如下一个场景. 一列键值对数据,存储在一个table中,如何通过数据的关键字快速查找相应值呢?不要告诉我一个 ...

  3. IOS应用在iPhone5和iPhone5s上不能全屏显示,应用画面上下各有1条黑色的解决方案

    设置启动图片就可以了: 添加启动图: 接着设置为启动图: 这样就ok了

  4. 【转】axios全攻略

    随着 vuejs 作者尤雨溪发布消息,不再继续维护vue-resource,并推荐大家使用 axios 开始,axios 被越来越多的人所了解.本来想在网上找找详细攻略,突然发现,axios 的官方文 ...

  5. AppDomain加载与释放dll

    AppDomain加载与释放dll 几年前写过同名随笔,但今天应不大适用了.但还有几个朋友留言关注,我重新发布相关代码. 首先我们的目的就是运行期间更新dll,并应用dll.这个过程需要应用 AppD ...

  6. appium的get_attribute方法

    转http://blog.csdn.net/bear_w/article/details/50330753 问题描述 当使用类似下面的代码获取元素的 content-desc 属性时,会报 NoSuc ...

  7. hdu4417(离线操作 + 树状数组)

    题意: 给定一个长度为n的数组,有m次的查询,每次查询[a,b]区间里比H小的数有多少个? 由于n和m的取值范围为0到10的5次方,所以直接回答会超时,所以考虑先读入所有的查询操作,然后依次回答比H小 ...

  8. 【184】FileZilla 搭建 FTP 及访问

    参考:FileZilla 下载中心 参考:使用FileZilla Server轻松搭建个人FTP服务器 建好后,Windows 访问:Windows徽标键+R打开运行窗口,输入ftp://*** ,* ...

  9. (图论)51NOD 1264 线段相交

    给出平面上两条线段的两个端点,判断这两条线段是否相交(有一个公共点或有部分重合认为相交). 如果相交,输出"Yes",否则输出"No".   输入 第1行:一个 ...

  10. play framework

    Compilation errorThe file {module:docviewer}/app/controllers/PlayDocumentation.java could not be com ...