文章目录
- STL 标准模板库
- 1、 STL简介
- 2、STL容器的类别
- 3、STL迭代器的类别
- 4、STL算法的类别
- 5、泛型编程(generic programming)
- 6、C++模板(template)
- 6.1 函数模板(function template)
- 6.2 类模板(class template)
STL 标准模板库
推荐 C++ 学习资料网站:C++ 参考手册
1、 STL简介
什么是STL:
- ⼀个强⼤的、可复⽤的、⾃适应的泛型类和函数集合
- 使⽤C++ 模板(templates)实现
- 实现了常⻅的数据结构(data structures)和算法(algorithms)
- 庞⼤的类库
- 俄裔美籍程序员:Alexander Stepanov 1994年开发
容器,算法,迭代器是独立设计的,但是它们之间配合的很好
- 容器(containers)
- 各种对象或原始类型的集合
- array、vector、deque、stack、set、map等
- 算法(algorithms)
- 处理容器元素序列的各种函数
- find、max、count、accumulate、sort等
- 迭代器(iterators)
- 从容器中⽣成元素的序列
- forward、reverse、by value、by reference、constant等
sort()算法需要使用元素的序列,这个时候需要使用到标准模板库中迭代器,使用 vec.begin() 和 vec.end() 可以将vec 的第一个元素到最后一个元素传给 sort,
accumulate(vec.begin(), vec.end(), 0) 中三个参数的表示是:vec.begin(), vec.end()表示迭代器,从哪里开始到哪里结束,0:表示累加的初始值,
2、STL容器的类别
- 序列式容器(sequence containers)
- array、vector、list、forward_list、deque
- 关联式容器(associate containers)
- set、multi set、map、multi map
- 容器适配器(container adapters),无法使用迭代器
- stack、queue、priority queue
3、STL迭代器的类别
- 输⼊迭代器(input iterators)
- 从容器到程序(对数据只读访问)
- 输出迭代器(output iterators)
- 从程序到容器(对数据只写访问)
- 前向迭代器(forward iterators)
- 向前推进迭代器(读写)
- 双向迭代器(bi-directional iterators)
- 向前、向后推进迭代器(读写)
- 随机访问迭代器(random access iterators)
- 直接获取容器元素(读写)
4、STL算法的类别
- 约60个算法
- ⾮质变的(non-modifying)
- 不会改变元素内容,如查找、计数等
- 质变的(modifying)
- 会改变元素内容,如拷⻉、替换、删除等
5、泛型编程(generic programming)
- 泛型编程
- 类型参数化
- 宏 Macro
- 函数模板(function template)
- 类模板(class template)
A、泛型编程
B、宏 Macro——不太推荐
下面的代码示例定义了 MAX 的宏,当预处理器看到 MAX 的时候会将参数自动替换为 a, b, 需要注意预处理器只会做简单的替换,并不懂C++语法,所以编译器编译的时候可能会出错,
如下图示例,预处理器只会做简单的替换,
使用括号,避免出现问题,
6、C++模板(template)
- 蓝图(blueprint)
- 函数和类模板,模板的核心思想就是类型的参数化,这样就可以根据实际需要来替换类型
- 可以动态替换任何数据类型
- 编译器会根据蓝图⽣成合适的函数和类
- 泛型编程(generic programming)/元编程(Meta-programming)
6.1 函数模板(function template)
将类型泛化成⼀个名称,⽐如:T,当然也可以使用其他合法的标识符,
- 告诉编译器这是函数模板
- 同时告诉它 T 是模板参数
- 这段代码可以通过编译,但不会生成任何代码,只有当调用这个模板时编译器才会生成具体的函数,
• 此时编译器会根据模板⽣成合适的函数
• 发⽣在编译阶段
• 编译器可以根据c和d的类型猜出T的类型
• 适⽤于⼏乎任何类型
• 这个类型必须⽀持 > 操作符
• 可以有多个模板参数
• 他们的类型可以不⼀样
代码:
#include <iostream>
#include <string>
using namespace std;
template <typename T>
T min_func(T a, T b)
{
return a < b ? a : b;
}
template <class T1, class T2>
void display(T1 a, T2 b)
{
cout << a << " " << b << endl;
}
int main()
{
// std::cout << min_func<int>(1, 2) << std::endl;
// std::cout << min_func(1, 2) << std::endl;
// std::cout << min_func('B', 'A') << std::endl;
// std::cout << min_func(3.3, 2.2) << std::endl;
// std::cout << min_func(5 + 2 * 9, 7 + 2 * 4) << std::endl;
display<int, int>(1, 2);
display(20, 30);
display<char, double>('A', 3.3);
display("Hello", "World");
display(2000, string{"Hello"});
return 0;
}
6.2 类模板(class template)
- 类似函数模板
- 允许各种类型的替换
- 编译器会根据蓝图⽣成特定的类
- vector 和 智能指针也是通过类模板实现的,
A
B
C
D
代码:
#include <iostream>
#include <string>
#include <vector>
using namespace std;
template <typename T>
class Item
{
private:
std::string name;
T value;
public:
Item(std::string name, T value)
: name{name}, value{value}
{
}
std::string get_name() const { return name; }
T get_value() const { return value; }
};
template <typename T1, typename T2>
struct My_pair
{
T1 first;
T2 second;
};
int main()
{
// Item<int> item1{"alice", 100};
// cout << item1.get_name() << " " << item1.get_value() << endl;
// Item<string> item2{"bob", "C++"};
// cout << item2.get_name() << " " << item2.get_value() << endl;
// Item<Item<string>> item3{"carol", {"david", "C++"}};
// cout << item3.get_name() << " " << item3.get_value().get_name() << " " << item3.get_value().get_value() << endl;
// vector<Item<double>> vec;
// vec.push_back(Item<double>("Frank", 100.0));
// vec.push_back(Item<double>("George", 200.0));
// vec.push_back(Item<double>("Harry", 300.0));
// for (const auto &item : vec)
// cout << item.get_name() << " " << item.get_value() << endl;
cout << "=====================" << endl;
My_pair<std::string, int> p1{"hello", 100};
My_pair<int, double> p2{200, 3.14};
cout << p1.first << " " << p1.second << endl;
cout << p2.first << " " << p2.second << endl;
return 0;
}