C++泛型一:模板
数据类型给程序设计带来的困扰及解决方案
int maxt(int, int);
double maxt(double, double);
若有一种占位符T
,能够代替类型,便可以简化代码的冗余编写
T maxt(T,T);
C++模板
模板声明如下
template<typename T1, ...>
template
是C++的模板声明关键字,尖括号内为模板参数列表
typename
为类型占位符声明关键字
template<typename T>
T maxt(T x, T y){
return (x>y)? x: y;
}
函数模板
在预编译阶段,当程序中调用函数模板时,编译器会用实际类型替换类型占位符生成实体函数
若编译器可以从函数实参中推导出模板参数所需类型,则可以不传入模板参数
template<typename T>
T maxt(T x, T y){
return (x>y)?x:y;
}
int main(int argc, char* argv[]){
// std::cout<< maxt<int>(4,6)<< std::endl;
std::cout<< maxt(4,6)<< std::endl;
return 0;
}
类模板
在声明类时,使用template
进行模板声明即可
template<typename T>
class Circle{
public:
Circle(T r);
}
若在类模板外实现成员函数,则必须声明为函数模板
template<typename T>
Circle<T>::Circle(T r){}
在调用时,需要在类名后使用尖括号传递具体类型
Circle<int> circle;
STL的模板编程对面向对象技术并不感兴趣,其认为类对数据的过度封装影响程序的执行效率
而为了更好的管理代码,所以STL中使用大量没有访问权限的struct
制作的类模板
变量模板
变量模板,将模板扩展到变量
如pi<T>
的实现
当T
为double
时,返回3.14
当T
为int
时,返回3
当T
为string
时,返回"3.14"
或"pi"
C++新标准对泛型设计的努力
auto和decltype
C++11中,auto
关键字,用来推导变量的数据类型auto a=100;
auto
类型的获取可通过编译器的类型记忆能力或decltype
的类型提示来推导
利用类型记忆推导复杂类型
auto
目前能力有限,只对系统的内置数据类型有效
对于用户自定义类型或复杂类型,只有当编译器取得足够经验后,才具备推导能力
map<int,map<int,int>>::const_iterator iter1=map1.begin();
auto iter2=map1.begin();
由于前一条语句告知了编译器map1.begin()
的类型,在处理第二条语句时,便利用了记忆能力自动推导出iter2
的类型
decltype
表达式对推导函数返回值类型进行指导
变量类型难以确定的问题一般出现在函数返回值上,C++11可以使用decltype
对函数返回值的类型推导工作进行指导
当返回auto
类型,需要编译器对函数返回值类型进行推导时,可用decltype
对该推导工作进行指导
template<typename T, typename U>
auto Multiply(T t, U u)->decltype(t*u){
return t*u;
}
这种使用auto
作为函数返回值类型的称为auto返回值占位
将auto
看作数据类型,则auto
也是一种泛型,只不过无须关键字typename
声明
且实际类型不是由实参显式提供,而是根据类型操作相关历史记忆及应用程序提供的推导思路
模板参数
根据参数实参的性质,模板参数分为类型参数,非类型参数和模板定义型参数三种
类型参数
用关键字typename
声明的参数
类型参数的类型实参包括:
- 系统内置的类型
- 用户自定义的数据类型
- 编译器刚学到的类模板实体
- 由
typename
定义的类型别名
非类型参数
C++允许在模板参数列表中定义普通变量或对象,如template<typename T, int a>
由于模板参数是在预编译阶段进行传递并被编译的,故这种非类型参数在模板代码内是常量,不能修改
对于这种参数,目前C++仅支持整型int
(或可转为int
的类型,如bool
),枚举,指针和引用类型
C++11支持非类型参数在定义时赋值,如template<typename T, int b=100>
模板定义型参数
以类模板作为类模板参数,除了强调这个类型参数必须为类模板外,还强调该类模板的参数个数
// 单模板参数的类模板
template<typename T>
struct S_Tmp{};
// 多模板参数的类模板
template<typename T, typename R>
struct D_Tmp{};
// 以单参数类模板作为参数的类模板
template<template<typename S>class T>
struct MyTest{};
int main(){
MyTest<S_Tmp> tt1;
// MyTest<D_Tmp> tt1; // error
return 0;
}
模板形参和实参的结合
函数模板实参的隐式结合
编译器可以根据函数实参类型推导出模板形参所对应的实参,这种在调用函数模板时可以省略模板参数列表
由于函数调用语句中不提供函数返回值的类型信息,所以模板的返回值类型占位符必须与某个形参的占位符相同
指针实参
C++中,指针是一种数据类型,因此可作为模板实参
修饰字const和&的使用
可以在模板调用参数列表中使用修饰字const
和&
template<typename T1, typename T2>
const T1& add(const T1& a, const T2& b){
return a;
}
模板特例化与模板具现
模板特例化
数据类型的变化通常与业务逻辑无关
若有个别数据类型所对应的算法与其他类型对应的算法不同,这类算法就要单独编写
函数模板的特化
如判断大小的函数,数值类型与字符串类型的比较算法是不一样的,应该分开实现
template<typename T>
T mymax(T a, T b){
return a>b?a:b;
}
template<>
char* mymax(char* a, char* b){
return (strcmp(a,b)<0)?b:a;
}
使用template<>
是为了将其纳入maxt
模板体系
类模板的特化与偏特化
// 普通模板
template<typename T1, typename T2>
struct Test{};
// 偏特化模板
template<typename T>
struct Test<int, T>{};
// 全特化模板
template<>
struct Test<int, float>{};
模板的具现
编译器在匹配模板生成实体代码时的优先级
- 特化模板(函数或类)
- 偏特化模板(类)
- 普通模板(函数或类)
C++泛型一:模板的更多相关文章
- Java泛型和集合之泛型VS模板
Java的泛型很像C++中的模板,说到Java 泛型和C++中的模板的关系时,有两个重要的方面需要被考虑到:语法和语义.语法看起来是相似的,可是语义却明显是不同的. 在语法上讲,选择尖括号 是因为他 ...
- chap1 C++泛型技术基础--模板 #STL
0 缘起 有一点编程经验和积累,想系统的学习下STL,以前都是随意做的笔记,现在想着成主题的输出一下. 书的原型是ISBN:9787302421757 <C++泛型STL原理和应用>,是从 ...
- 模板singleton模式的C++实现
模板singleton模式的C++实现 近期回过头整理了一下singleton模式,看了别人写的关于singleton的介绍.发现这个singleton模式虽然简单,但要写一个稳定/线程安全/泛型的模 ...
- c++模板 与 泛型编程基础
C++模板 泛型编程就是以独立于任何特定类型的方式编写代码,而模板是泛型编程的基础. (1)定义函数模板(function template) 函数模板是一个独立于类型的函数,可以产生函数的特定类型版 ...
- C++ template —— 实例化和模板实参演绎(四)
本篇讲解实例化和模板实参演绎-------------------------------------------------------------------------------------- ...
- 存储过程分页 Ado.Net分页 EF分页 满足90%以上
存储过程分页: create proc PR_PagerDataByTop @pageIndex int, @pageSize int, @count int out as select top(@p ...
- C++的头文件和实现文件分别写什么
在C++编程过程中,随着项目的越来越大,代码也会越来越多,并且难以管理和分析.于是,在C++中就要分出了头(.h)文件和实现(.cpp)文件,并且也有了Package的概念. 对于以C起步,C#作为& ...
- 设计模式之Inheritance versus Parameterized Types 继承和参数化类型
Another (not strictly object-oriented)technique for reusing functionality is through parameterized t ...
- Java和C++的区别
这是一个Java语言和C++语言之间的比较. 目录 [隐藏] 1 设计目标 2 语言特性 2.1 语法 2.2 语义 2.3 资源管理 2.4 库 2.5 运行时 2.6 模板 vs. 泛型 2.7 ...
- C# .Net基础知识点解答
原文地址 1. 什么是.NET?什么是CLI?什么是CLR?IL是什么?JIT是什么,它是如何工作的?GC是什么,简述一下GC的工作方式? 通俗的讲,.Net是微软开发应用程序的一个平台: CLI是C ...
随机推荐
- 在lcd屏幕上的任意位置显示任意大小的图片
/************************************************* * * file name:ShowBmp2.c * author :momolyl@126.co ...
- .NET 8 + Blazor 多租户、模块化、DDD框架、开箱即用
前言 基于 .NET 8 的开源项目,主要使用 WebAPI + Blazor 支持多租户和模块化设计,DDD构建.可以帮助我们轻松地搭建起一个功能完善的Web应用程序.除了帮助你快速构建应用程序之外 ...
- 基于MonoGame重制《俄罗斯方块》游戏
两年前,我使用C#基于MonoGame编写了一款<俄罗斯方块>游戏,相关介绍可以参考[这篇文章].最近,使用业余时间将之前的基于MonoGame的游戏开发框架重构了一下,于是,也就趁此机会 ...
- 一种PyInstaller中优雅的控制包大小的方法
PyInstaller会在打包时自动为我们收集一些依赖项,特别是我们在打包PyQt/PySide相关的应用时,PyInstaller会自动包含我们程序通常不需要的文件,如'tanslations'文件 ...
- NYX靶机笔记
NYX靶机笔记 概述 VulnHub里的简单靶机 靶机地址:https://download.vulnhub.com/nyx/nyxvm.zip 1.nmap扫描 1)主机发现 # -sn 只做pin ...
- el-popover - 问题
背景:elemet - ui和vue , el-table中使用了 el-popover , el-popover 中使用了form, 每编辑一行数据,点击编辑按钮,出现el-popover弹窗,页面 ...
- Python存储与读写二进制文件
技术背景 一般情况下我们会选择使用明文形式来存储数据,如json.txt.csv等等.如果是需要压缩率较高的存储格式,还可以选择使用hdf5或者npz等格式.还有一种比较紧凑的数据存储格式,就是直接按 ...
- 技术解析 | ZEGO 移动端超分辨率技术
即构超分追求:速度更快.效果更好.码率更低.机型更广. 超分辨率(Super Resolution, SR)是从给定的低分辨率(Low Resolution, LR)图像中恢复高分辨率(High ...
- 『读书笔记』你不知道的JavaScript(上)
前言 文章只记录理解以及容易遗忘的知识点. 词法作用域.块作用域 词法作用域 词法作用域:简单的说,词法作用域就是定义在词法阶段的作用域.换句话说,词法作用域就是在你写代码时将变量和块作用域写在哪里来 ...
- Redis 入门 - 收官
<Redis 入门>系列文章总算完成了,希望这个系列文章可以想入门或刚入门的同学提供帮助,希望能让你形成学习Redis系统性概念. 当时为什么要写这个系列文章,是因为我自己就是迷迷糊糊一路 ...