模版

模版在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. 较大主干网的ISP通常控制信道利用率不超过50%

    信道利用率 网络利用率  加权平均值

  2. Java 负载均衡

    什么是负载均衡 负载均衡,英文 名称为Load Balance,指由多台服务器以对称的方式组成一个服务器集合,每台服务器都具有等价的地位,都可以单独对外提供服务而无须其他服务器的辅助.通过某种 负载分 ...

  3. Object Query Language (OQL) query 基本使用

    OQL是对java堆内存进行查询分析 使用方法: 1.查看java线程id jps -lvm 上图红框中的为pid: 2.运行命令-导出堆内存信息-会生成一份文件在你本地 jmap -dump:liv ...

  4. HDU1024 Max Sum Plus Plus —— DP + 滚动数组

    题目链接:http://acm.split.hdu.edu.cn/showproblem.php?pid=1024 Max Sum Plus Plus Time Limit: 2000/1000 MS ...

  5. i节点,容易被人遗忘的节点

    部分内容转自点击打开链接 点击打开链接 前段时间做了RHCE的一道题,是iSCSi的,后来在挂载的时候说是磁盘被占用.当时资料找了很多结果还是没有找到解决方法.反倒是发现了这个inode,也是关于被占 ...

  6. 工作中常用到的JS校验

    1. // 验证是否为空 2. function check_blank(obj, obj_name){ 3. if(obj.value != ''){ 4. return true; 5. }els ...

  7. 常见电商项目的数据库表设计(MySQL版)

    转自:https://cloud.tencent.com/developer/article/1164332 简介: 目的: 电商常用功能模块的数据库设计 常见问题的数据库解决方案 环境: MySQL ...

  8. WordPress xmlrpc.php flaw exploited to install a WSO 2.1 Web Shell by oRb

    WordPress xmlrpc.php flaw exploited to install a “WSO 2.1 Web Shell by oRb” Below you can see in the ...

  9. Find offset of first/last found substring

    DATA: TEXT TYPE STRING VALUE 'RO_LL_OVER BEET_HOVEN', MOFF TYPE I VALUE '-1'. FIND FIRST OCCURRENCE ...

  10. vue2.0构建单页应用最佳实战

    链接: https://www.tuicool.com/articles/me6RJfF