模版

模版在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. Day1 BFS算法的学习和训练

    ​ 因为自己的原因,之前没有坚持做算法的相应学习,总是觉得太难就半途而废,真的算是一个遗憾了,所以现在开始,定一个30天入门学习算法计划. ​ 我是根据<算法图解>的顺序进行安排的,自己对 ...

  2. JDBC+XML+DOM4J

    利用xml文件封装数据库配置信息xml文件放在src目录下/testjdbc1/src/DBUtil.xml <?xml version="1.0" encoding=&qu ...

  3. YTU 1001: A+B Problem

    1001: A+B Problem 时间限制: 1 Sec  内存限制: 10 MB 提交: 4864  解决: 3132 [提交][状态][讨论版] 题目描述 Calculate a+b 输入 Tw ...

  4. 网站图片增强JS插件2.0(兼容IE&FF)

    网站图片增强JS插件2.0简单介绍:插件可以增强网站互动能力与外链建设,用户在欣赏图片的同时,把看好的图片直接制作成自己喜欢的样式后通过QQ等传播,增强外链建设,通过用户互动创造外链.(支持:放大缩小 ...

  5. 性能测试工具curl-loader(linux)

    curl-loader介绍 curl-loader(也被称为“omes-NIK”和“davilka”)是一个开源的C语言编写的工具,模拟应用负载和成千上万的几十万人的HTTP / HTTPS和FTP/ ...

  6. go语言godep使用命令

    godep 看见他的star比govendor,所以我使用它.官方地址 https://github.com/tools/godep install   1 go get github.com/too ...

  7. 【140】◀▶ ArcGIS技巧

    目录: Add XY Data 图例修改 中文字符左斜体设置 专题图只显示“度” 制作渐变图例 待定 待定 待定 1. 在ArcGIS中插入含有经纬度的*.txt或者*.xls文件等 File> ...

  8. 从事UNIX/LInux服务器编程最方便的代码编译工具------(eclipse for c/c++)、(FileZilla)、(Secure CRT) 这三种一定要一起使用 之1

    今天主要是将前几天搞的Linux学习的心得写出来,希望帮助更多的人进行,方便从事Unix和Linux编程的同行和刚入门者.主要介绍三种工具并给出安装过程,请大家不必怀疑这个博文,此博文是我自己原创.请 ...

  9. vs2010统计代码行数

    参考:http://www.cnblogs.com/zfanlong1314/archive/2013/03/08/2950100.html 正则表达式:^:b*[^:b#/]+.*$ 文件类型:*. ...

  10. IE6 浏览器常见兼容问题 大汇总(23个)[转载]

    IE6以及各个浏览器常见兼容问题 大汇总 综述:虽然说IE6在2014年4月将被停止支持,但是不得不说的是,IE6的市场并不会随着支持的停止而立刻消散下去,对于WEB前端开发工程师来说,兼容IE6 兼 ...