模版

模版在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_闭包详解

    http://blog.csdn.net/chenglc1612/article/details/53413318 一.变量的作用域 要理解闭包,首先必须理解Javascript特殊的变量作用域. 变 ...

  2. arm位清零bic指令

    (1)指令的语法格式 BIC{<cond>}{S} <Rd>,<Rn>,<shifter_operand> BIC(Bit Clear)位清零指令,将寄 ...

  3. ZOJ3261 Connections in Galaxy War —— 反向并查集

    题目链接:https://vjudge.net/problem/ZOJ-3261 In order to strengthen the defense ability, many stars in g ...

  4. 关于页面上输入框中 空格 、0 、NULL 的处理 示例

    ep.setPositionNum(get("positionNum").toString()); ep.setClasstype(get("classtype" ...

  5. web前端技术社区分享

    web前端技术社区分享 一.国外的前端技术网站:    1. 名称:W3C: 网址:http://www.w3.org/ 理由:前端技术的规范标准几乎都是W3C制定的  2.名称:ECMA 网址:ht ...

  6. C# mouse keyboard monitor

    /*********************************************************************************** * C# mouse keyb ...

  7. Java总结基础知识

    权限关键字: public:可以被所有其他类所访问,不同的包 protected:当前类的成员.同一个包中.不同包中对子类可见父类protected,继承类 default:同一包中的类可以访问,声明 ...

  8. Python基础第十天

    一.内容

  9. 01_传智播客iOS视频教程_课程介绍与知识点回顾

    OC语法中static关键字不能修饰属性,也不能修饰方法,只能修饰方法中的局部变量.static修饰局部变量之后把局部变量变成静态变量.当方法执行完之后这个变量不会被回收.下次再执行这个方法的时候这个 ...

  10. wireshark笔记(1)之工具认识

    1 下载链接  https://www.wireshark.org/ 安装只需要注意同时会安装winpcap就好了 相关链接:www.wiresharkbook.com //书籍 英文 www.wik ...