part 1 C++模版简介

一,模版概观

1.模板 (Templates)是C++的一种特性,允许函数或类(对象)通过泛型(generic types)的形式表现或运行。

 模板可以使得函数或类在对应不同的型别(types) 的时候正常工作,而无需为 每一个型别都写一份代码。

2.C++主要有两种类型的模板:

  (1)类模板(Class template): 使用泛型参数的类(classes with generic parameters)

  (2)函数模板(Function template): 使用泛型参数的函数(functions with generic parameters)

3.模版实例化  

  模板的声明(declaration)其实并未给出一个函数或类的完全定义(definition),只是提供了一个函数或类的语法框架(syntacticalskeleton)。

  实例化是指从模板构建出一个真正的函数或类的过程,比如:

template <typename T> struct Object { . . . };

可以用来构建诸如Object<int>, Object<char>, Object<int*>, Object<MyClass*>等等不同型别的具体实例。

  实例化有两种类型:

  (1)显式实例化–在代码中明确指定要针对哪种型别进行实例化。
  (2)隐式实例化–在首次使用时根据具体情况使用一种合适的型别进行实例化。

二,模版函数

4.函数模版

 定义:函数模板是参数化的一族函数(a family of functions)。

 通过函数模板, 可以定义一系列函数,这些函数都基于同一套代码,但是可以作用在不同型别的参数上。

template <typename T>
T max(const T& a, const T& b)
{
return (a>b) ? a : b;
}

  也可以使用 class 来代替 typename , 但是不推荐使用。

5.模版的使用

int i = , j = ;
max(i, j); // 正确 int f = 3.1, g = 4.2
max(f, g); //正确 max(i, f); //错误
//compile error: template parameter 'T' is ambiguous

6. 模版实例化

 用具体型别替代模板参数T的过程叫做实例化(instantiation);从而产生了一个模板实例

 一旦使用函数模板,这种实例化过程便由编译器自动触发的,不需要额外去请求模板实例化。

 如果实例化一种型别,而该型别内部并不支持函数所使用的操作,那么就会导致一个编译错误。

 例如:std::complex并没有重载“>”,也就是说该型别并不支持使用“>”比较大小,而Max函数使用“>”来判断c1、c2的大小,所以无法通过Max(complex1, complex2)得到预期的结果。

 结论: 模板被编译了两次
  1)没有实例化之前,检查模板代码本身是否有语法错误。
  2)实例化期间, 检查对模板代码的调用是否合法。

7.参数推导

  模板参数是有传递给模板函数的实参决定的不允许自动型别转换:每个T必须严格匹配!

Max(, ) // OK:两个实参的型别都是 int
Max(, 2.0) // ERROR:第一个参数型别是 int,第二个参数型别是 double

  一般有两种处理这种错误的方法:

    1) 用 static_cast或强制转换参数型别以使两者匹配。
    2) 显式指定T的型别。

Max(static_cast<double>(), 2.0)
Max<double>(, 2.0)

8.函数模版重载

  (1)重载:函数模板也可以像普通函数一样被重载
  (2)同名:非模板函数可以和同名的模板函数共存
  (3)参数推导:编译器通过函数模板参数推导来决定使用调用哪个重载

// 普通函数
inline int const& Max(const int const& a, const int const& b) // 第一个 template <typename T>
inline T const& Max(const T const& a, const T const& b) // 第二个 template <typename T>
inline T const& Max(const T const& a, const T const& b, const T const& c) // 第三个

  Max(7, 42, 68): 调用接受三个参数的模板 // 调用 第三个
  Max(7.0, 42.0): 调用 Max<double>(参数推导) // 调用 第二个
  Max('a', 'b'): 调用 Max<char>(参数推导) // 调用 第二个
  Max(7, 42): 调用非模板函数,参数型别为 int // 调用 第一个 其他因素都相同的情况下,重载裁决过程调用非模板函数,而不是从模板产生实例
  Max<>(7, 42): 调用 Max< int>(参数推导) // 调用 第二个 允许空模板参数列表
  Max<double>(7, 42): 调用 Max<double>(无需参数推导) // 调用 第二个
  Max('a', 42.7): 调用非模板函数,参数型别为 int // 调用 第一个 对于型别不同的参数只能调用非模板函数( char 型别 'a' 和 double 型别 42.7 都将转化为 int 型别)

  总结
    对于不同的实参型别,模板函数定义了一族函数
    当传递模板实参的时候,函数模板依据实参的型别进行实例化
    可以显式指定模板的实参型别
    函数模板可以重载
    当重载函数模板时, 将改变限制在:显式指定模板参数
    所有的重载版本的声明必须位于它们被调用的位置之前

三,类模版

  1.1与函数模版类似,类也可以通过函数参数泛化,从而可以构建出一族不同型别的类实例(对象)。

   1.2 类模版实参可以是某一型别或常量(仅限int或enum)。

  2. 类模版实例

const std::size_t DefaultStackSize = ;
template<typename T, std::size_t n = DefaultStackSize>
class Stack
{
public:
void Push(const T const& element);
int Pop(T& element);
int Top(T& element) const;
private:
std::vector<T> m_Members;
std::size_t m_nMaxSize = n;
};

  n是编译时定义的常量,n可以有默认值。

  3.类模板的声明

  除了 Copy constructor 之外,如果在类模版中需要使用到这个类本身,比如 operator= ,那么应该使用其完整的定义(Stack<T>),而不是省略型别 T 。如下面的例子所示: 

template <typename T, std::size_t n>
class Stack
{
public:
Stack(Stack<T, n> const&); // copy constructor
Stack<T>& operator= (Stack<T, n> const&); //assignment operator
};

 4. 类模板的实现

  要定义一个类模板的成员函数,则要指明其是一个模版函数。

 4.1 例如,Push 函数的定义应当如下:

template <typename T, std::size_t nMaxSize>
void Stack<T, nMaxSize>::Push(const T const& element)
{
if (m_Members.size() >= m_nMaxSize)
{
//error handing ...
return;
} m_Members.push_back(element);
}

 4.2 Pop 函数:从 Stack 中弹出顶部元素,但是没有 pop 出该元素:

template <typename T, std::size_t nMaxSize>
int Stack<T, nMaxSize>::Top(T& element) const
{
if (m_Members.empty())
return ; element = m_Members.back();
return ;
}

STL与泛型编程(第一周)的更多相关文章

  1. STL与泛型编程-第一周笔记-Geekband

    1, 模板观念与函数模板 简单模板: template< typename T > T Function( T a, T b) {- } 类模板: template struct Obje ...

  2. STL与泛型编程第一周作业

    /* 题目: 给定一个 vector:v1 = [0, 0, 30, 20, 0, 0, 0, 0, 10, 0],希望通过not_equal_to 算法找到到不为零的元素,并复制到另一个 vecto ...

  3. STL 入门 (17 暑假集训第一周)

    快速全排列的函数 头文件<algorithm> next_permutation(a,a+n) ---------------------------------------------- ...

  4. 第一周 总结笔记 / 斯坦福-Machine Learning-Andrew Ng

    课程主页:https://www.coursera.org/learn/machine-learning/home/welcome 收集再多的资料也没用,关键是要自己理解总结,做笔记就是一个归纳总结的 ...

  5. Surprise团队第一周项目总结

    Surprise团队第一周项目总结 团队项目 基本内容 五子棋(Gobang)的开发与应用 利用Android Studio设计一款五子棋游戏,并丰富其内涵 预期目标 实现人人模式:2个用户可以在同一 ...

  6. 20145213《Java程序设计》第一周学习总结

    20145213<Java程序设计>第一周学习总结 教材学习内容总结 期待了一个寒假,终于见识到了神秘的娄老师和他的Java课.虽说算不上金风玉露一相逢,没有胜却人间无数也是情理之中,但娄 ...

  7. 20145206邹京儒《Java程序设计》第一周学习总结

    20145206 <Java程序设计>第1周学习总结 教材学习内容总结 1.三大平台:Java SE.Java EE与Java ME.Java SE是各应用平台的基础,分为四个主要的部分: ...

  8. 20145304 刘钦令 Java程序设计第一周学习总结

    20145304<Java程序设计>第1周学习总结 教材学习内容总结 1995年5月23日,是公认的Java的诞生日,Java正式由Oak改名为Java. Java的三大平台是:Java ...

  9. 20145330孙文馨 《Java程序设计》第一周学习总结

    20145330孙文馨 <Java程序设计>第一周学习总结 教材学习内容总结 刚开始拿到这么厚一本书说没有压力是不可能的,开始从头看觉得很陌生进入不了状态,就稍微会有一点焦虑的感觉.于是就 ...

  10. 20145337《JAVA程序设计》第一周学习总结

    # 20145337 <Java程序设计>第1周学习总结 ## 教材学习内容总结 第一章 -Java最早是Sun公司撰写Star7应用程序的程序语言 -根据应用领域不同,有Java SE. ...

随机推荐

  1. tkinter 进度条

    import tkinter as tk window = tk.Tk() window.title("我的窗口") window.geometry('600x400') var1 ...

  2. 解决windows系统的oracle数据库不能启动ora-00119和ora-00130的问题

    SQL>startup 报错ora-00119 ora-00130 出现上述错误应该是数据库的监听文件出了问题,修改listener.ora文件: # listener.ora Network ...

  3. maven报错集

    1.install报错解决[致命错误: 在类路径或引导类路径中找不到程序包 java.lang] Windows分隔符英文分号 <bootclasspath>${java.home}/li ...

  4. IP报文

      位字段的值设置为二进制的0100表示IP版本4(IPv4).设置为0110表示IP版本6(IPv6)   位,它表示32位字长的IP报头长度,设计报头长度的原因是数据包可选字段大小会发生变化.IP ...

  5. Redis压力测试

    然后依次测试如下命令: 上面第三个命令写错了,要改为:

  6. Django +uwsgi+python3+nginx + mysql 部署

    环境: 服务器ip:192.168.0.110 centos服务器 6.4 + mysql 5.6 + django1.11 +nginx 1.13.7 + uwsgi 2.0.18 uwsgi介绍 ...

  7. MySQL 5.7怎么爬出暂时表空间的坑

    版权声明:本文为博主原创文章.未经博主同意不得转载. https://blog.csdn.net/n88Lpo/article/details/78126267 导读 怎样确认暂时表是由哪个用户连接创 ...

  8. [vue]webpack&vue组件工程化实践

    [vue]全局组件和局部组件(嵌套+props引用父组件数据) [vue]组件篇 [vue]组件的创建(componet)和销毁(keep-alive缓存)和父子dom同步nextTick [vue] ...

  9. 机器学习理论基础学习3.3--- Linear classification 线性分类之logistic regression(基于经验风险最小化)

    一.逻辑回归是什么? 1.逻辑回归 逻辑回归假设数据服从伯努利分布,通过极大化似然函数的方法,运用梯度下降来求解参数,来达到将数据二分类的目的. logistic回归也称为逻辑回归,与线性回归这样输出 ...

  10. [lr] 常用快捷键

    界面基本操作 F5               : 隐藏/显示上部面板 F6               : 隐藏/显示下部面板 F7               : 隐藏/显示左部面板 F8     ...