Pair和Tuple

一、Pair 类

pair类定义在<utility>中,定义如下:

template<class _Ty1,
class _Ty2>
struct pair
{ // store a pair of values
typedef pair<_Ty1, _Ty2> _Myt;
typedef _Ty1 first_type;
typedef _Ty2 second_type;

        ......

_Ty1 first; // the first stored value
_Ty2 second; // the second stored value

        ......

        }

pair是一个类模板,定义为struct,因此内部成员都为public。

pair可以将两个value视为一个单元,C++中多处用到了pair类型。如容器:map、multimap、unorder_map、unorder_multimap都是以pair来管理其key/value形式的元素。

Pair和Tuple

pair支持拷贝构造、移动构造(支持隐式转换),重载了赋值运算符及比较操作符。

p.first与get<0>(p)返回pair的第一个成员;p.second与get<1>(p)返回pair的第二个成员。注意:get()为C++11用法,需要使用支持C++11的编译器。

函数make_pair可以返回一个pair对象。

另外提供了一个p.swap(q)的成员函数和swap(p,q)的全局函数用于交换两个pair的值。

二、Tuple 类

tuple是一个可变模板类,用于存储任意数量类型的实参。

自C++11后,可变模板(variadic template)被引进,tuple简单的定义如下:

template<class...>

class tuple;

tuple可以用于以下几点:

· 作为结构的轻量级替代品

· 用于从函数返回多个值

· 执行值集合的比较

Pair和Tuple

可以通过以下方式实例化tuple:

tuple<int,int,bool> x;//实例化但是不初始化

tuple<int,string> y{2,"hello"};//实例化并初始化

auto z = make_tuple(2,3,4,"bye");//实例化并通过make_tuple函数进行初始化

要获得tuple的值,需要使用get<>()函数:

auto tuple_test = std::make_tuple(2,3.14,"test");

auto int_test = std::get<0>(tuple_test);//得到2

auto string_test = std::get<2>(tuple_test);//得到test;

索引从0开始,可以依次获取tuple的值。

如果需要通过tuple改变一个既有值,可以使用引用包装器(reference_wrapper<>)及便捷函数ref()、cref(),下面事一个例子:

std::string str;

auto tuple_test1 = std::make_tuple(str);//tuple_test1 是一个tuple<string>类型

std::get<0>(tuple_test1) = "test";//修改了tuple_test1但是没有修改str


auto tuple_test2 = std::make_tuple(ref(str));//tuple_test2是一个tuple<string&>类型,tuple_test2指向str

std::get<0>(tuple_test2) = "test";//既修改了tuple_test2又修改了str的值


通过reference搭配make_tuple(),可以方便地提取tuple的值并赋值给变量,如下:

std::tuple<int,float,std::string> tuple_test{2,3.14,"test"};

int i;

float j;

std::string str;

std::make_tuple(std::ref(i),std::ref(j),std::ref(str)) = tuple_test;//将tuple_test的值赋值给了i、j、str


如果想更方便地在tuple中使用reference,可以使用tie(),它可以建立一个内含reference的tuple,如下:

std::tuple<int,float,std::string> tuple_test{2,3.14,"test"};

int i;

float j;

std::string str;

std::tile(i,j,str) = tuple_test;

使用tie时,可以通过std::ignore让我们忽略一些元素,可用于局部提取tuple的值,如下:

std::tuple<int,float,std::string> tuple_test{2,3.14,"test"};

int i;

std::string str;

std::tie(i,std::ignore,str) = tuple_test;


tuple的构造函数声明为explicit,因此避免了隐式转换,可以使用初值列表(initializer list)定义tuple内容。注意不可以使用赋值语法初始化tuple,会被视为一个隐式转换,如:std::tuple<int,double> = {2,3.14}//error。

此外不可以将initializer list传入到一个知识期望获取tuple的地方。

std::vector<std::tuple<int,float>> v{{1,1,0},{2,2,0}};//error

std::tuple<int,int,int> foo(){

        return {1,1,1};

}//error

这种做法对于pair和出了array<>外的容器是可行的,但是对于tuple,必须明确的将初值转为tuple。

std::tuple<int,int,int> foo(){

        return std::make_tuple(1,1,1);

}


std::using tuple_test = std::tuple<int,float,std::string>;

std::tuple_size<tuple_test >::value;//return 3,返回tuple元素类型的个数

std::tuple_element<tuple_test ,1>::type;//return float,返回指定元素的类型


int i =0;

float j = 1;

auto tuple_test = std::tuple_cat(std::make_tuple(1,2,"test"),std::tie(i,j);//串接多个tuple


Pair和Tuple