• 模板参数

函数模板,编译器根据实参来为我们推断模板实参。

模板中可以定义非类型参数,表示一个值而非一个类型,这些值必须是常量表达式,从而允许编译器在编译时实例化模板。

非类型参数可以是整型,或者一个指向对象或函数的指针或(左值)引用。绑定到前者的实参必须是常量表达式,绑定到后者的必须具有静态生存期。

  • 泛型代码两个原则

1模板中的函数参数是const的引用

2函数体中的条件判断仅适用<比较运算

第一条保证了函数可以用于不能拷贝的类型

第二条降低了对要处理类型的要求,模板应该尽量减少对实参类型的要求

  • 实例化
模板的头文件通常既包含声明也包括定义
模板提供者保证模板被实例化时,模板的定义(包括成员的定义)都必须是可见的。
用户需保证用来实例化模板的所有函数、类型以及类型关联的运算符声明都必须是可见的。 成员函数只有在被用到时才进行实例化。使得某些不完全复合模板操作要求的类型也能实例化类,但是不能用那些特性的操作。
在类模板自己的作用域中可以直接使用模板名而不提供实参,在外部必须提供
template <typename T>
BlobPtr<T> BlobPtr<T>::operator++(int)
{ BlobPtr ret=*this;//里面不需要
} 需要先前置声明为模板,将模板的一个特定实例声明为友元时
一对一友好关系
friend class BlobPtr<T>;
friend bool operator==<T> (const Blob<T>&, const Blob<T>&); 通用友好关系
template <typename X> friend class Pal2;//不需要前置声明,使用不同的模板参数X
  • 类型别名
typedef只能医用实例化的类
dypedef Blob<string> StrBlob;
新标准允许为类模板定义一个类型别名
template <typename T> using twin=pair<T, T>;
twin<string> authors;//authors是一个pair<string, string>
类型别名可以固定一个或多个模板参数
template <typename T> using partNo=pair<T, unsigned>; 一个特定文件用到所有模板声明通常一起放在文件的开始位置。不必担心编译器由于未遇到你希望调用的函数而实例化一个并非你需要的版本。 C++默认通过作用域访问的名字不是类型,所以如果我们希望使用模板类型参数的类型成员,必须显式地告诉编译器该名字是一个类型。
template <typename T>
typename T::value_type top(const T& c) //返回类型是一个类型
  • 可以为函数和类模板提供默认实参。

无论何时使用类模板必须在模板名后加上尖括号,如果所有模板参数都提供了默认实参,而我们又希望使用默认实参,则加一个空的尖括号。

  • 成员模板不能是虚函数
在类外定义时,同时为类模板和成员模板提供模板参数列表
template <typename T>
template <typename It>
Blob<T>::Blob(It b, It e); 多个文件中实例化相同模板有额外开销,在大系统中可能非常严重
可以显式实例化,声明必须在任何使用此实例版本的代码之前
extern template class Blob<string>; // 实例化声明
template int compare(cons tint&, cons tint&);//实例化定义
显式实例化的类模板,必须能用于模板的所有成员
  • 效率和灵活性
运行时绑定删除器,删除器是间接保存的,调用del(p)时需要一次运行时的跳转操作
del ? del(p) : delete p;// del(p)需要运行时跳转到del的地址 编译时绑定
del(p); //直接调用实例化的删除器,无运行时额外开销
  • 能应用于函数模板的类型转换
1const转换:非const对象的引用(或指针)传递给const的引用(指针)形参
2数组或函数:如函数形参不是引用,可以对数组或函数类型的实参应用正常的指针转换
如函数参数类型不是模板参数,则可以进行正常类型转换。
  • 函数模板显式实参
1编译器无法推断(如返回类型) 2希望允许用户控制模板实例化
template < typename T1, typename T2, typename T3>
T1 sum(T2, T3); auto val3= sum<long long>(i, lng); //long long sum(int, lonog)
显式模板实参由左至右的顺序与对应的模板参数匹配。
由于尾至返回出现在参数列表之后,它可以使用函数的参数
template < typename It>
auto fcn(It beg, It end) -> decltype(*beg)

有时我们无法直接获得所需要的类型

  • 标准类型转换模板

    对Mod,其中Mod为 |若T为 |则Mod::type为|

    |remove_reference| X&或X&&| X|

    ||否则| T|

    |add_count| X&、const X或函数|T|

    ||否则 |const T|

    |add_lvalue_reference| X&|T|

    ||X&&|X&|

    ||否则 |T&|

    |add_rvalue_reference |X&或X&&|T|

    ||否则| T&&|

    |remove_pointer |X|X|

    ||否则| T|

    |add_pointer |X&或X&&|X
    |

    ||否则| T*|

    |make_signed| unsigned X|X|

    ||否则 |T|

    |make_unsigned| signed X|unsigned X|

    ||否则|T|

    |remove_extent| X[n]|X|

    ||否则| T|

    |remove_all_extents| X[n1][n2]…|X|

    ||否则| T|

template void f1(T&); // 实参必须是一个左值

template void f2(const T&); // 实参可以接受一个右值

template void f3(T&&); // 可以右值,也可以左值

  • 右值引用,move,forward
通常一个右值引用不能绑定到一个左值。
两个例外
1当将一个左值传递给函数的右值引用,且此右值引用指向模板类型参数(如T&&)时,编译器推断模板类型参数为实参的左值引用类型。调用f3(i),T推断为int&
通常不能定义一个引用的引用,但是通过类型别名或通过模板类型参数间接定义是可以的
2如果我们间隔创建一个引用的引用,则这些引用形成了折叠
X& &、X& &&和X&& &都折叠为类型X&
X&& &&折叠为X&& 所以一个函数参数是指向模板参数类型的右值引用,则可以传递给他任意类型的实参。它对应实参的const属性和左右值属性得到保持。
通常用于模板转发其实参或模板被重载。
重载通常按以下方式来
template <typename T> void f(T&&); //绑定到非const右值
template <typename T> void f(const T&) //绑定到左值和const右值 std::move的函数参数T&&是一个指向模板类型参数的右值引用,经过引用折叠可以与任何类型的实参匹配,返回都是一个右值引用
static_cast指针右值引用的特例:显式地将左值转换为一个右值引用 当用于一个指向模板参数类型的右值引用函数参数时,forward会保持实参类型的所有细节。
template <typename T> void f(T &&arg)
{
g(std::forward<T>(arg));
}
首先选择更好的匹配,对于同样好的匹配
优先选择非模板函数
其次是更特例化的模板
如果找不出更好的,则此调用有歧义。
  • 可变参数模板
template <typename T, typename…Args>
void foo(const T &t, const Args& … rest);
sizeof…(Args)知道参数包中元素的个数,不会对实参求值 可变参数函数通常是递归的。为了终止递归需要定义一个非可变参数版本,否则会无限递归。 包扩展就是将它分解为构成的元素,对每个元素应用模式。通过在模式右边放一个省略号来触发扩展。
template < typename…Args>
ostream& errMsg(ostream &os, const Args& … rest)
{
return print(os, debug_rep(rest)…);
} 转发参数包
alloc.construct(first_free++, std::forward<Args>…);
  • 模板特例化
1通用模板的定义对特定类型不适合
2可以利用特定知识来编写更搞笑的代码
template <> //尖括号指出我们将为原模板所有模板参数提供实参
一个特例化版本本质上是一个实例,而不是函数名的一个重载版本
一个特殊的函数定义是特例化版本还是一个独立的非模板函数,会影响到函数匹配。 为了特例化一个模板,原模板的声明必须在作用域中。而且,在任何使用模板实例的代码之前,特例化版本的声明也必须在作用域中。
通常模板及特例化版本应该声明在同一个头文件中。所有同名木板的声明应该放在前面,然后是这些模板的特例化版本。 为了让Sales_data的用户能使用hash的特例化版本,我们应该在Sales_data的头文件中定义该特例化版本 偏特化只能作用于类模板,而不能用于函数模板
偏特化模板参数列表是原模板的一个子集或者是一个特例化版本
template <typename T> struct remove_reference template <typename T> struct remove_reference<T&>
template <typename T> struct remove_reference<T&&> 可以只特例化成员而不是类
template<>
void Foo<int>::Bar()

C/C++基础--模板与泛型编程的更多相关文章

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

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

  2. C++ 模板与泛型编程

    <C++ Primer 4th>读书笔记 所谓泛型编程就是以独立于任何特定类型的方式编写代码.泛型编程与面向对象编程一样,都依赖于某种形式的多态性. 面向对象编程中的多态性在运行时应用于存 ...

  3. C++ Primer 学习笔记_75_模板与泛型编程 --模板定义

    模板与泛型编程 --模板定义 引言: 所谓泛型程序就是以独立于不论什么特定类型的方式编写代码.使用泛型程序时,我们须要提供详细程序实例所操作的类型或值. 模板是泛型编程的基础.使用模板时能够无须了解模 ...

  4. C++ Primer(6) 模板和泛型编程(上)

    问题聚焦: 泛型编程是独立于变量类型的方式编写代码: 模板是泛型编程的基础. 本篇主要介绍模板的基础知识,包括:模板的定义和模板的实例化. 1 模版定义 必要性: Demo int compare(c ...

  5. C++ 模板 与 泛型编程

    C++ 模板 与 泛型编程 前言 模板有两种:类模板和函数模板 .模板是泛型编程的基础. 什么叫:泛型编程? 使用独立于特定类型的方式进行编程.也就是我们在编程的时候不明确的写上类型,而是使用一个模板 ...

  6. 【c++ Prime 学习笔记】第16章 模板与泛型编程

    面向对象编程(OOP)和泛型编程(GP)都能处理在编写程序时类型未知的情况 OOP能处理运行时获取类型的情况 GP能处理编译期可获取类型的情况 标准库的容器.迭代器.算法都是泛型编程 编写泛型程序时独 ...

  7. C++ Primer 学习笔记_76_模板与泛型编程 --模板定义[续]

    模板与泛型编程 --模板定义[续] 四.模板类型形參 类型形參由keywordclass或 typename后接说明符构成.在模板形參表中,这两个keyword具有同样的含义,都指出后面所接的名字表示 ...

  8. C++ Primer 学习笔记_84_模板与泛型编程 --模板特化

    模板与泛型编程 --模板特化 引言: 我们并不总是能够写出对全部可能被实例化的类型都最合适的模板.某些情况下,通用模板定义对于某个类型可能是全然错误的,通用模板定义或许不能编译或者做错误的事情;另外一 ...

  9. C++ Primer 学习笔记_77_模板与泛型编程 --实例化

    模板与泛型编程 --实例化 引言: 模板是一个蓝图,它本身不是类或函数.编译器使用模板产生指定的类或函数的特定版本号.产生模板的特定类型实例的过程称为实例化. 模板在使用时将进行实例化,类模板在引用实 ...

随机推荐

  1. Cython 使用

    链接: Cython是一个快速生成Python扩展模块的工具,从语法层面上来讲是Python语法和C语言语法的混血,当Python性能遇到瓶颈时,Cython直接将C的原生速度植入Python程序,这 ...

  2. 将数据存入mysql中

    import pymysql import warnings # 忽略警告 warnings.filterwarnings("ignore") # 连接数据库 db = pymys ...

  3. Unity 3D接入ShareSDK流程2

    Unity开发VR之Vuforia 本文提供全流程,中文翻译. Chinar 坚持将简单的生活方式,带给世人!(拥有更好的阅读体验 -- 高分辨率用户请根据需求调整网页缩放比例) Chinar -- ...

  4. this和super用法详解

    这几天看到类在继承时会用到this和super,这里就做了一点总结,与各位共同交流,有错误请各位指正~ this this是自身的一个对象,代表对象本身,可以理解为:指向对象本身的一个指针. this ...

  5. dfs——皇后问题(回溯)

    #include <iostream> using namespace std; ],b[],c[],d[]; ; dfs(int i) { if(i>n) { sum++; ) { ...

  6. bulma入门

    http://www.ruanyifeng.com/blog/2017/10/bulma.html

  7. PS学习之合成特效:被风沙侵蚀的动物们

    素材 大象 尘埃 裂纹 沙子 土地 正式操作: 打开PS 新建一个文件 选国际标准纸张  给分辨率为72(分辨率越大越占内存) 然后确定  将图片旋转90度(图像——旋转——(顺/逆)90度) 下面选 ...

  8. eclipse项目版本控制忽略上传文件

    *.classpath *.project */.git/* .deployables .git .settings .svn _svn bin target

  9. LG3187 [HNOI2007]最小矩形覆盖

    题意 题目描述 给定一些点的坐标,要求求能够覆盖所有点的最小面积的矩形,输出所求矩形的面积和四个顶点坐标 输入输出格式 输入格式: 第一行为一个整数n(3<=n<=50000),从第2至第 ...

  10. day25scala

    PS:1.scala是开发spark平台的一种语言.2.如果开发spark的话,用scala开发是非常好的,Python的话一般,用java的话就是效果不好. -------------------- ...