std::pair
在“泛型”一章,曾动手写过“Pair”,相当于自造了一个轮子,
因为C++标准库提供了类似的实现:std::pair。pair提供一对成员,两个成员的类型,分别通过模板参数指定,比如:
#include <utility> /**< 包含pair及关系比较小工具 */
......
std::pair <int, std::string> num_name;
num_name.first = 10;
num_name.second = "Tom";
std::pair <std::string, double> name_price;
name_price.first = "Apple";
name_price.second = 4980.00;
//也支持在构造时直接初始化:
std::pair <int, double> tmp(10, 2.3);
pair在标准库中一个典型的应用,就是作为std:map容器内部存储的元素。
map容器可称为“映射表”或“键值对”,它的每一个元素都由两个成员组成,第一个成员作为“KEY”,第二个成员称为“(VALUE)值”。
map容器会在内部根据“(KEY)键”对元素进行排序。用户通过“KEY”快速找到元素,而用户实际需要的,往往是“VALUE”的内容。通过“pair”结构,用户可以幸福美满而简单地实现在一起。
std::tuple
std::tuple支持让0个,1个,以及多个数据“捆绑”在一起。其中0个和1个没多大意义,2个则可以找“std::pair”,所以应从3个说起。
#include <tuple>
......
std::tuple <int, string, double> t3(100, "table", 89.20);
构造对象和pair一致,但入和取出这其中三个成员就很不相同了,first second third ……这样的思路,
tuple提供成员函数“get <int> ()”来访问内部成员数据:
int score = t3.get<0>();
string name = t3.get<1>();
double price = t3.get<2>();
一旦一个turple由模板出一个类型(class),则这个class又会拥有一个成员模板函数,大致长这个样子(示意代码):
template <int Index>
T const& get <int Index> () const
{
...
}
既然这是一个函数模板,那么当传入的Index值不同,就会生成不同的函数,也就是说:get<0>()和get<1>()是两个不同的函数。
一个“3-tuple”的类,会有三个get<int>()函数,这是在编译时,就决定下来的,所以对例中的“t3”对象,不能幻想可以调用它的第4个访问元素:
t3.get<3>();
这个错误不需要等到运行期爆发,编译器就会报错。
正是因为需要在编译器就生成具体的函数(模板->函数),所以上例才能做到,每一个get<>(),都已经有一个明确的返回值了,它可不像any需在运行期去猜与试
比如对于t3, get <0>()返回的是int,get <2>()返回的是double,错不了。
正因为是需要在编译期就生成具体的函数(模板->函数),所以也不能幻想给get传一个变量,期望在运行期再决定取哪个成员:
int i
cin >> i;
??? = t3.get <i> ();//错
想要循环输出一个tuple内部的各个成员,这样看似朴素的梦想,也破灭了:
for(int i = 0; i < 3; ++i)
cout << t3.get<i>();
想象以下,如果要制造一个“10-tuple”的对象,光写它的类型名称,就有够长的了,所以stl分别提供了make_tuple和make_pair函数,方便我们直接造出一个tuple或pair对象。假设我们有一个map:
std::map <int, double> a_map;
要万里面添加成员(pair对象),方法一:
std::pair <int, string> pair_1(10, 0.1);
a_map.insert(pair_1);
方法二,使用make_pair函数:
a_map.insert(std::make_pair(10, 0.1));
当然,对于map,也可以使用:“a_map[10] = 0.1;”。make_tuple函数用法和make_pair类似:
make_tuple(10, 0.2); //生成一个tuple<int, double>对象
//生成一个tuple<string(), vector <string>>对象,
//俩成员的值都是各自类型的默认构造的初始化值:
make_tuple(string(), vector <string> ());
//可以嵌套:
make_tuple(100, "ABC", 12.3, make_tuple(10, 0.4));
最后,无论是pair还是tuple,都支持保存一个对象的引用(而非复制品):
int i = 100;
std::pair <int&, double> tmp2(i, 0.0);
++ tmp2.first;
cout << i << endl;
不过,如果要使用make_pair()函数生成一个pair<int&, double>对象,如何写呢?下面的代码实现不了:
int i = 10;
pair <int &, double> tmp = make_pair(i, 1.2);
这段代码编译不能通过,make_pair函数生成的对象类型是 pair<int, double>, 而不是tmp类型, 这就需要学习STL提供的“引用”小工具 。