数据类型给程序设计带来的困扰及解决方案

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>的实现

Tdouble时,返回3.14

Tint时,返回3

Tstring时,返回"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>{};

模板的具现

编译器在匹配模板生成实体代码时的优先级

  1. 特化模板(函数或类)
  2. 偏特化模板(类)
  3. 普通模板(函数或类)

C++泛型一:模板的更多相关文章

  1. Java泛型和集合之泛型VS模板

    Java的泛型很像C++中的模板,说到Java 泛型和C++中的模板的关系时,有两个重要的方面需要被考虑到:语法和语义.语法看起来是相似的,可是语义却明显是不同的. 在语法上讲,选择尖括号  是因为他 ...

  2. chap1 C++泛型技术基础--模板 #STL

    0 缘起 有一点编程经验和积累,想系统的学习下STL,以前都是随意做的笔记,现在想着成主题的输出一下. 书的原型是ISBN:9787302421757 <C++泛型STL原理和应用>,是从 ...

  3. 模板singleton模式的C++实现

    模板singleton模式的C++实现 近期回过头整理了一下singleton模式,看了别人写的关于singleton的介绍.发现这个singleton模式虽然简单,但要写一个稳定/线程安全/泛型的模 ...

  4. c++模板 与 泛型编程基础

    C++模板 泛型编程就是以独立于任何特定类型的方式编写代码,而模板是泛型编程的基础. (1)定义函数模板(function template) 函数模板是一个独立于类型的函数,可以产生函数的特定类型版 ...

  5. C++ template —— 实例化和模板实参演绎(四)

    本篇讲解实例化和模板实参演绎-------------------------------------------------------------------------------------- ...

  6. 存储过程分页 Ado.Net分页 EF分页 满足90%以上

    存储过程分页: create proc PR_PagerDataByTop @pageIndex int, @pageSize int, @count int out as select top(@p ...

  7. C++的头文件和实现文件分别写什么

    在C++编程过程中,随着项目的越来越大,代码也会越来越多,并且难以管理和分析.于是,在C++中就要分出了头(.h)文件和实现(.cpp)文件,并且也有了Package的概念. 对于以C起步,C#作为& ...

  8. 设计模式之Inheritance versus Parameterized Types 继承和参数化类型

    Another (not strictly object-oriented)technique for reusing functionality is through parameterized t ...

  9. Java和C++的区别

    这是一个Java语言和C++语言之间的比较. 目录 [隐藏]  1 设计目标 2 语言特性 2.1 语法 2.2 语义 2.3 资源管理 2.4 库 2.5 运行时 2.6 模板 vs. 泛型 2.7 ...

  10. C# .Net基础知识点解答

    原文地址 1. 什么是.NET?什么是CLI?什么是CLR?IL是什么?JIT是什么,它是如何工作的?GC是什么,简述一下GC的工作方式? 通俗的讲,.Net是微软开发应用程序的一个平台: CLI是C ...

随机推荐

  1. 高考志愿填报指南:使用AI阅读工具ChatDOC搭建专业、好用、免费的AI高考志愿填报系统

    高考志愿填报指南:使用 ChatDOC 搭建专业.好用.免费的 AI 高考志愿填报系统 不说废话,直接上干货.针对高考志愿填报,这篇文章能为你提供以下内容:高考志愿填报专业数据.高考志愿填报分析思路. ...

  2. RabbitMq消息可靠性之确认模式 通俗易懂 超详细 【内含案例】

    RabbitMq保证消息可靠性之确认模式 介绍 消息的确认,是指生产者投递消息后,如果 Broker 收到消息,则会给我们生产者一个应答.生产者进行接收应答,用来确定这条消息是否正常的发送到 Brok ...

  3. Camera | 8.让rk3568支持前后置摄像头

    一.目标 本文主要目标是,支持前置摄像头0v5648.后置摄像头ov13850,以及移植过程遇到的一些小问题的解决. 1. 摄像头连接图 参考上图,摄像头详细信息如下: 2个摄像头均连接在I2C通道4 ...

  4. Linux下SPI驱动详解

    更多嵌入式原创文章,请关注公众号:一口Linux 1. SPI总线 1.1. SPI总线概述 SPI,是英语Serial Peripheral interface的缩写,顾名思义就是串行外围设备接口. ...

  5. MySql 字段类型长度问题理解

    mysql中字段长度理解 字符长度 设计表中设置的是字符长度,任意字符都占一个字符长度,使用char_length 函数获取 char_length(`name`) 字节长度 字节长度和数据表的字符集 ...

  6. Dapr v1.14 版本已发布

    Dapr是一套开源.可移植的事件驱动型运行时,允许开发人员轻松立足云端与边缘位置运行弹性.微服务.无状态以及有状态等应用程序类型.Dapr能够确保开发人员专注于编写业务逻辑,而不必分神于解决分布式系统 ...

  7. 【YashanDB数据库】YAS-00413 wait for receive timeout

    [问题分类]错误码处理 [关键字]yasql,00413 [问题描述]使用工具设置不同并发迁移数据的过程中,导致yasql登录报错:YAS-00413 wait for receive timeout ...

  8. Dart 2.12 现已发布

    作者 / Michael Thomsen Dart 2.12 现已发布,其中包含 健全的空安全 和 Dart FFI 的稳定版.空安全是我们最新主打的一项生产力强化功能,意在帮助您规避空值错误,以前这 ...

  9. 运输小猫娘之再续 5k 传奇之寻找人道主义素数

    原文 前情提要 本章主角 5k_sync_closer 第一章 从再续前缘到苦心寻找满足最优条件的人道主义美丽素数 上回书说到,5k 因为拯救大家被炸断了 \(1000000007\) 米中的十五千米 ...

  10. T2回家(home)题解

    T2回家(home) 现在啥也不是了,虽然会了逆元,但是对期望概率题还是一窍不通,赛时相当于只推出了 \(n=1\) 的情况,结果运用到所有情况,理所应当只有20分. 题目描述 小Z是个路痴.有一天小 ...