STL与泛型编程(第一周)
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与泛型编程(第一周)的更多相关文章
- STL与泛型编程-第一周笔记-Geekband
1, 模板观念与函数模板 简单模板: template< typename T > T Function( T a, T b) {- } 类模板: template struct Obje ...
- STL与泛型编程第一周作业
/* 题目: 给定一个 vector:v1 = [0, 0, 30, 20, 0, 0, 0, 0, 10, 0],希望通过not_equal_to 算法找到到不为零的元素,并复制到另一个 vecto ...
- STL 入门 (17 暑假集训第一周)
快速全排列的函数 头文件<algorithm> next_permutation(a,a+n) ---------------------------------------------- ...
- 第一周 总结笔记 / 斯坦福-Machine Learning-Andrew Ng
课程主页:https://www.coursera.org/learn/machine-learning/home/welcome 收集再多的资料也没用,关键是要自己理解总结,做笔记就是一个归纳总结的 ...
- Surprise团队第一周项目总结
Surprise团队第一周项目总结 团队项目 基本内容 五子棋(Gobang)的开发与应用 利用Android Studio设计一款五子棋游戏,并丰富其内涵 预期目标 实现人人模式:2个用户可以在同一 ...
- 20145213《Java程序设计》第一周学习总结
20145213<Java程序设计>第一周学习总结 教材学习内容总结 期待了一个寒假,终于见识到了神秘的娄老师和他的Java课.虽说算不上金风玉露一相逢,没有胜却人间无数也是情理之中,但娄 ...
- 20145206邹京儒《Java程序设计》第一周学习总结
20145206 <Java程序设计>第1周学习总结 教材学习内容总结 1.三大平台:Java SE.Java EE与Java ME.Java SE是各应用平台的基础,分为四个主要的部分: ...
- 20145304 刘钦令 Java程序设计第一周学习总结
20145304<Java程序设计>第1周学习总结 教材学习内容总结 1995年5月23日,是公认的Java的诞生日,Java正式由Oak改名为Java. Java的三大平台是:Java ...
- 20145330孙文馨 《Java程序设计》第一周学习总结
20145330孙文馨 <Java程序设计>第一周学习总结 教材学习内容总结 刚开始拿到这么厚一本书说没有压力是不可能的,开始从头看觉得很陌生进入不了状态,就稍微会有一点焦虑的感觉.于是就 ...
- 20145337《JAVA程序设计》第一周学习总结
# 20145337 <Java程序设计>第1周学习总结 ## 教材学习内容总结 第一章 -Java最早是Sun公司撰写Star7应用程序的程序语言 -根据应用领域不同,有Java SE. ...
随机推荐
- tkinter 进度条
import tkinter as tk window = tk.Tk() window.title("我的窗口") window.geometry('600x400') var1 ...
- 解决windows系统的oracle数据库不能启动ora-00119和ora-00130的问题
SQL>startup 报错ora-00119 ora-00130 出现上述错误应该是数据库的监听文件出了问题,修改listener.ora文件: # listener.ora Network ...
- maven报错集
1.install报错解决[致命错误: 在类路径或引导类路径中找不到程序包 java.lang] Windows分隔符英文分号 <bootclasspath>${java.home}/li ...
- IP报文
位字段的值设置为二进制的0100表示IP版本4(IPv4).设置为0110表示IP版本6(IPv6) 位,它表示32位字长的IP报头长度,设计报头长度的原因是数据包可选字段大小会发生变化.IP ...
- Redis压力测试
然后依次测试如下命令: 上面第三个命令写错了,要改为:
- 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介绍 ...
- MySQL 5.7怎么爬出暂时表空间的坑
版权声明:本文为博主原创文章.未经博主同意不得转载. https://blog.csdn.net/n88Lpo/article/details/78126267 导读 怎样确认暂时表是由哪个用户连接创 ...
- [vue]webpack&vue组件工程化实践
[vue]全局组件和局部组件(嵌套+props引用父组件数据) [vue]组件篇 [vue]组件的创建(componet)和销毁(keep-alive缓存)和父子dom同步nextTick [vue] ...
- 机器学习理论基础学习3.3--- Linear classification 线性分类之logistic regression(基于经验风险最小化)
一.逻辑回归是什么? 1.逻辑回归 逻辑回归假设数据服从伯努利分布,通过极大化似然函数的方法,运用梯度下降来求解参数,来达到将数据二分类的目的. logistic回归也称为逻辑回归,与线性回归这样输出 ...
- [lr] 常用快捷键
界面基本操作 F5 : 隐藏/显示上部面板 F6 : 隐藏/显示下部面板 F7 : 隐藏/显示左部面板 F8 ...