Part 9: 模板与泛型编程(第16章)

// @author:       gr
// @date: 2016-03-18
// @email: forgerui@gmail.com

1. 模板参数

  1. 类型模板参数

    类型可以是类类型或内置类型,通过typename或class修饰类型。

     //T是一个类型
    template <typename T>
    void func(const T & rhs) {
    //....
    }
  2. 非类型模板参数

    非类型参数表示一个值,不需要typename,直接使用特定类型名修饰:

     template <unsigned N, unsigned M>
    void func(const char (&p1)[N], const char (&p2)[M]) {
    return strcmp(p1, p2);
    //...
    }

    我们可以如下调用

     compare("hi", "kitty");

    编译器会使用字面常量的大小来代替N和M。因此编译器会实例化出如下版本:

     int compare(const char(&p1)[3], const char (&p2)[6]);

2. 模板编译

为了生成一个具现化模板,编译器需要掌握函数模板或类模板的定义。

因此,模板的头文件通常既包括声明也包括定义

编译器会在三个阶段报错:

第一个阶段是编译器模板本身。

第二个阶段是编译器遇到模板使用时。

第三个阶段是模板实例化时,只有这个阶段才能发现类型相关的错误。

3. 类模板

接受一个initializer_list参数:

template <typename T>
Blob<T>::Blob(std::initializer_list<T> il) : data(std::make_shared<std::vector<T>>(il)) {}

一个实例化的类模板,其成员只有在使用时才进行实例化。

4. 类模板名的简化

在类内,可以简化类模板名,去掉模板类型名。

在类外,必须使用完整的类模板名

5. 模板友元

一个类可以将另一个模板的每个实例都声明为友元,或者限定特定的实例为友元:

template <typename T>
class C {
//C的每个实例将相同实例化Pal声明为友元
firend class Pal<T>;
//Pal2的所有实例都是C的每个实例的友元
template <typename X> friend class Pal2;
//Pal3是一个非模板类,它是C所有实例的友元
friend class Pal3;
};

6. 模板类型别名

可以使用typedef定义指定的类型参数模板:

typedef Blob<string> StrBlob;

但不能用typedef引用一个模板,即typedef无法引用Blob。

但新标准允许定义为类模板定义一个类型别名:

template <typename T> using twin = pair<T, T>;
twin<string> authors; //相当于pair<string, string> authors;

7. 类模板的static成员

相同模板参数实例化的类之间才共享静态变量和静态函数。

8. 默认模板实参

可以提供默认模板实参,新标准可以为函数和类模板提供默认实参。以前只允许为类模板提供默认实参。

template <typename T, typename F = less<T>>
int compare(const T &v1, const T &v2, F f = F()) {
if (f(v1, v2)) return -1;
if (f(v2, v1)) return 1;
reutrn 0;
}

调用时,可以提供自己的比较操作,但并不必需:

bool i = compare(0, 42);

Sales_data item1(cin), item2(cin);
bool j = compare(item1, item2, compareIsbn);

9. 模板默认实参与类模板

如果类模板为其所有模板参数都提供了默认实参,如果要使用这些默认实参,就必须在模板名之后跟一个空尖括号对:

template<class T = int>
class Numbers {
public:
Numbers(T v = 0) : val(v) {}
private:
T val;
}; Numbers<long double> lots_of_precision;
Numbers<> average_precision; // 空<>表示我们希望使用默认参数

10. 类模板的成员模板

类模板中的成员函数也可以定义成模板,如果这个成员模板在模板类外定义,那要写两个模板参数列表:

template <typename T>   //类的类型参数
template <typename It> //函数的类型参数
Blob<T>::Blob(It b, It e) {
//...
}

11. 模板类型转换

模板只接受两种类型转换:

  1. 非const转const:将非const引用对象转换为const引用对象
  2. 指针转换:数组实参可以转换为指向其首元素的指针,函数实参可以转换为该函数类型的指针

其它的类型都不能被自动转换。

12. 函数模板显式实参

函数模板如果位于参数中,可以直接通过参数列表推导出来。

函数模板如果参数类型是返回值,这样就无法自动推导出来,这样就需要在函数后显式指定。

template <typename T1, typename T2, typename T3>
T1 func(T2, T3); auto val1 = func<string>(1, 1.0); //可以,相当于string func(int, double)
auto val2 = func<string, int, double>(1, 1.0); //可以,全部显式指定

省略的参数类型必须放在显式指定的后面,否则不能省略,全部类型都要显式给出:

template <typename T1, typename T2, typename T3>
T3 func(T1, T2);
auto val1 = func<string>(1, 1.0); //错误
auto val2 = func<int, double, string>(1, 1.0); //可以,必须全部给出类型

13. 正常类型转换应用于显式指定的实参

上面11条说模板不支持大多数的转换,但如果模板实参已经被显式指定,那么这种转换就可以进行。

template <typename T>
void func(T, T); long lng;
func(lng, 1024); //无法进行,两个参数不一致,且支持类型转换
func<int>(lng, 1024); //可以进行,long被转换成int
func<double>(lng, 1024); //可以进行,两者都被转换为double

### 学习《C++ Primer》- 9的更多相关文章

  1. Python学习--04条件控制与循环结构

    Python学习--04条件控制与循环结构 条件控制 在Python程序中,用if语句实现条件控制. 语法格式: if <条件判断1>: <执行1> elif <条件判断 ...

  2. Python学习--01入门

    Python学习--01入门 Python是一种解释型.面向对象.动态数据类型的高级程序设计语言.和PHP一样,它是后端开发语言. 如果有C语言.PHP语言.JAVA语言等其中一种语言的基础,学习Py ...

  3. Python 学习小结

    python 学习小结 python 简明教程 1.python 文件 #!/etc/bin/python #coding=utf-8 2.main()函数 if __name__ == '__mai ...

  4. Python学习路径及练手项目合集

    Python学习路径及练手项目合集 https://zhuanlan.zhihu.com/p/23561159

  5. python学习笔记-python程序运行

    小白初学python,写下自己的一些想法.大神请忽略. 安装python编辑器,并配置环境(见http://www.cnblogs.com/lynn-li/p/5885001.html中 python ...

  6. Python学习记录day6

    title: Python学习记录day6 tags: python author: Chinge Yang date: 2016-12-03 --- Python学习记录day6 @(学习)[pyt ...

  7. Python学习记录day5

    title: Python学习记录day5 tags: python author: Chinge Yang date: 2016-11-26 --- 1.多层装饰器 多层装饰器的原理是,装饰器装饰函 ...

  8. [Python] 学习资料汇总

    Python是一种面向对象的解释性的计算机程序设计语言,也是一种功能强大且完善的通用型语言,已经有十多年的发展历史,成熟且稳定.Python 具有脚本语言中最丰富和强大的类库,足以支持绝大多数日常应用 ...

  9. Python学习之路【目录】

    本系列博文包含 Python基础.前端开发.Web框架.缓存以及队列等,希望可以给正在学习编程的童鞋提供一点帮助!!! 目录: Python学习[第一篇]python简介 Python学习[第二篇]p ...

  10. python学习笔记系列----(八)python常用的标准库

    终于学到了python手册的最后一部分:常用标准库.这部分内容主要就是介绍了一些基础的常用的基础库,可以大概了解下,在以后真正使用的时候也能想起来再拿出来用. 8.1 操作系统接口模块:OS OS模块 ...

随机推荐

  1. 基于RealSense的坐姿检测技术

    计算机的飞速普及,让人们将越来越多的工作放在计算机上去完成,各行各业,尤其是程序开发人员.文字工作者,在计算机上的工作时间越来越长,这种情况下不良的坐姿对颈肩腰椎都会产生很大影响,容易导致多种疾病的发 ...

  2. 2015南阳CCPC A - Secrete Master Plan 水题

    D. Duff in Beach Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 无 Description Master Mind KongMing gave ...

  3. C#实现汉诺塔问题

    汉诺塔的由来:汉诺塔是源自印度神话里的玩具.上帝创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上安大小顺序摞着64片黄金圆盘.上帝命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上.并且 ...

  4. Python的包管理工具Pip

    接触了Ruby,发现它有个包管理工具RubyGem非常好用,而且有非常完备的文档系统http://rdoc.info 发现Python下也有相同的工具,包含easy_install和Pip.只是,我没 ...

  5. IOS App动态更新

    框架 JSPatch WaxPatch react-native   方案对比 目前已经有一些方案可以实现动态打补丁,例如WaxPatch,可以用Lua调用OC方法,相对于WaxPatch,JSPat ...

  6. android之多媒体篇(三)

    录像 Android提供了2种方案去录像. 方案一: 最简单的方式就是使用Intents去启动App来帮助你完成.这个方案使你能够指定输出的位置和视频的质量.这方案通常是最好的方法,应该可以用在多种情 ...

  7. android应用程序ANR定义

    在Android上,如果你的应用程序有一段时间响应不够灵敏,系统会向用户显示一个对话框,这个对话框称作应用程序无响应(ANR:Application Not Responding)对话框.用户可以选择 ...

  8. HttpClient post json

    public static JSONObject post(String url,JSONObject json){ HttpClient client = new DefaultHttpClient ...

  9. 前端必会的js知识总结整理

    1.晨曦. 2.js是一门什么样的语言及特点?         js是一种基于对象和事件驱动的并具有相对安全性的客户端脚本语言.也是一种广泛用于web客户端开发的脚本语言,常用来给html网页添加动态 ...

  10. session超时和cookie过期

    一.Cookie的过期和Session的超时有什么区别? 会话的超时由服务器来维护,它不同于Cookie的失效日期.首先,会话一般基于驻留内存的cookie不是持续性的cookie,因而也就没有截至日 ...