C++多元组Tuple使用方法?你熟悉吗?快来看看吧

开发 后端
tuple 是类似于pair的模板。每个pair的成员类型都不相同,但每个pair都恰好有两个成员。不同tuole类型的也不相同,但一个tuple可以有任意数量的成员。每个确定的tuple类型的成员数目是固定的,但一个tuple类型的成员数目可以与另一个tuple类型不同。

[[350276]]

前言

tuple 是类似于pair的模板。每个pair的成员类型都不相同,但每个pair都恰好有两个成员。不同tuole类型的也不相同,但一个tuple可以有任意数量的成员。每个确定的tuple类型的成员数目是固定的,但一个tuple类型的成员数目可以与另一个tuple类型不同。

当我们希望将一些数据组合成单一对象,但又不想麻烦地定义一个新数据来表示这些数据时,tuple是非常有用的。

例如我们可以构造一个tuple 

  1. tuple<const char*, int>tp = make_tuple(sendPack,nSendSize); 

这个tuple等价于一个结构体

  1. struct A 
  2.   char* p; 
  3.   int len; 
  4. }; 

用tupletp就可以不用创建这个结构体了,而作用是一样的,是不是更简洁直观了

还有一种方法也可以创建元组,用std::tie,它会创建一个元组的左值引用。

  1. auto tp = return std::tie(1, "aa", 2); 

tp的类型实际是:

  1. std::tuple<int&,string&, int&> 

tuple初印象

tuple支持如下的操作

  1. std::tuple<T1, T2, ...TN> t;            //创建一个空的tuple对象(使用默认构造),它对应的元素分别是T1和T2...Tn类型,采用值初始化。 
  2. std::tuple<T1, T2, ...TN> t2(v1, v2, ... vn);    //创建一个tuple对象,它的元素分别是T1和T2 ...Tn类型; 每个成员用对应的vi进行初始化 
  3. std::tuple<T1&> t3(ref&); // tuple的元素类型可以是一个引用 

像pair一样也可以通过make_tuple进行创建一个tuple对象,tuple的类型从初始值的类型推断

  1. std::make_tuple(v1, v2);  

返回t的第i个数据成员的引用:如果t是一个左值,结果是一个左值引用;否则,结果是一个右值引用。此外tuple的所有成员都是pulic的。

  1. get<i>(t) 

我们可以将tuple看作一个“快速而随意”的数据结构。

定义和初始化tuple

当我们定义一个std::tuple时,需要指出每个成员的类型。

  1. tuple<size_t,size_t,size_t> threeD; //三个成员都被设置为0 
  2.  
  3. tuple<string,vector<doble>,int ,list<int>> someVal("constans",{3.14,2.718},42,{0,1,2,3,4,5}); 

当我们创建一个std::tuple对象时,可以使用tuple的默认构造函数,它会对每个成员进行值初始化;也可以向上面someVal初始化一样,为每个成员提供一个初始值,此时的构造函数是explicit的,因此必须使用直接初始化方法。

  1. tuple<size_t,size_t,size_t> htreeD = {1,2,3}; 
  2. tuple<size_t,size_t,size_t> htreeD(1,2,3); 

类似make_pair函数,标准库定义了make_tuple函数,我们还可以使用它来生成std::tuple对象。

  1. auto item = mak_tuple("0-999-78345-x",3,20.00); 

类似make_pair,make_tuple函数使用初始值的类型来推断tuple的类型。在上面示例中,item是一个tuple,类型为tuple .

访问tuple的成员

一个pair总是有两个成员,这样标准库就可以为他们命名(first和second),但是这种命名方法不适用于tuple,因为一个tuple的类型的成员数目是没有限制的。因为,tuple的成员都是未命名的。要访问一个tuple的成员,就要使用一个名为get的标准库函数模板。为了使用get,我们必须指定一个显示模板实参,它指出我们想要访问第几个成员。我们传递给get一个tuple对象,它返回指定成员的引用。

  1. auto book  = get<0>(iterm); //返回iterm的第一个成员 
  2. auto cnt  = get<0>(iterm); //返回iterm的第二个成员 
  3. auto price  = get<0>(iterm)/cnt; //返回iterm的第三个成员 

尖括号中的值必须是一个整型常量表达式,与平时一样,我们从0开始计数,意味着get<0>是第一个成员。

如果不知道tuple准确的类型细节信息,可以用两个辅助类模板查询tuole的成员的数量和类型:

1.一个类模板,可以通过一个tuple类型初始化,它有一个名为value的public constexpr static数据类型,类型为size_t,表示给定tuple类型中成员数量

  1. tuple_element<i,tupleType>::type 

2.一个类模板,可以通过一个整型常量和一个tuple类型来初始化。它有一个名为type的public成员,表示给定tuple类型中指定的类型

  1. tuple_size<tupleType>::value 

通过这两个类模板我们可以获得我们需要的tuple变量的成员数量和类型

  1. typedef decltype(item) trans;//trans是item的类型 
  2.  
  3. size_t sz = tuple_size< trans>::value;//返回trans类型对象中成员的数量 
  4.  
  5. tuple_element<1,trans>::type cnt ; // cnt 为 item第二个成员变量类型  int型 
  6.  
  7. cnt = get<1>(item); 

为了使用tuple_size或tuple_element,我们需要知道一个tuple对象的类型。与往常一样,确定一个对象的类型的最简单的方法就是使用decltype,在typedef decltype(item) trans;中,我们使用decltype来为item定义一个类型别名,用它来实例化这两个模板。

tuple_size有一个名为value的public static数据成员,它表示给定tuple中成员的数量。 tuple_element模板除了一个tuple类型外,还接受一个索引值。它有一个名为type的public类型成员,表示给定tuple类型中指定成员类型。类似get,tuple_element所使用的索引也是从0开始计数的。

std::tuple的关系和相等运算符的行为类似容器的对应操作。这些运算符逐对比较左侧tuple和右侧tuple的成员。只有两个tuple具有相同数量的成员时,我们才可以比较它们。而且,为了使用tuple的相等或不等运算符,对每对成员使用==运算符必须都是合法的;为了使用关系运算符,对每对成员使用 < 必须都是合法的。

关系和相等运算符:当两个tuole具有相同数量的成员且成员对应相等时,两个才tuple相同。

  1. tuple<string,string> duo("1","2"); 
  2. tuple<size_t,size_t> twoD(1,2); 
  3.  
  4. bool b = (duo == twoD); // 错误,不能比较size_t 和 string 
  5.  
  6. tuple<size_t,size_t,size_t> threeD(1,2,3); 
  7.  b = (duo == threeD); // 错误,成员数量不同 
  8. tuple<size_t,size_t> origin(0,0); 
  9.  b = (origin < twoD); // 正确:b为true 

由于tuple定义了<和==运算符,我们可以将tuple序列传递给算法,并且可以在无序容器中将tuple作为关键字类型。

利用tie进行解包元素的值

如同pair一样也是可以通过tie进行解包tuple的各个元素的值。如下tuple对象有4个元素,通过tie解包将会把这4个元素的值分别赋值给tie提供的4个变量中。

  1. int main(int argc, char **argv) { 
  2.     std::tuple<std::string, int, std::string, int> tp; 
  3.     tp = std::make_tuple("Sven", 25, "Shanghai", 21); 
  4.     // 定义接收变量 
  5.     std::string name
  6.     std::string addr; 
  7.     int ages; 
  8.     int areaCode; 
  9.   
  10.     std::tie(name, ages, addr, areaCode) = tp; 
  11.     std::cout << "Output: " << '\n'
  12.     std::cout << "name: " << name <<", "
  13.     std::cout << "addr: " << addr << ", "
  14.     std::cout << "ages: " << ages << ", "
  15.     std::cout << "areaCode: " << areaCode << '\n'
  16.     return 0; 

输出结果:

name: Sven, addr: Shanghai, ages: 25, areaCode: 21

但有时候tuple包含的多个元素时只需要其中的一个或两个元素,如此可以通过std::ignore进行变量占位,这样将会忽略提取对应的元素。可以修改上述例程:

  1. std::tie(name, ages, std::ignore, std::ignore) = tp; 

std::tuple中元素是被紧密地存储的(位于连续的内存区域),而不是链式结构。

如何遍历tuple成员

N表示tuple中的第N个元素

  1. #include <iostream> 
  2. #include <tuple> 
  3. #include <string> 
  4.   
  5. using namespace std; 
  6.   
  7. template<typename Tuple, int N = std::tuple_size<Tuple>::value> 
  8. struct Printer 
  9.   static void log(Tuple& t) { 
  10.     Printer<Tuple, N - 1>::log(t); 
  11.   
  12.     using type = typename std::tuple_element<N - 1, Tuple>::type; 
  13.     std::string ts = typeid(type).name(); 
  14.     type& v = std::get<N - 1>(t); 
  15.   
  16.     std::cout << ts << ":" << v << std::endl; 
  17.   } 
  18. }; 
  19.   
  20. template<typename Tuple> 
  21. struct Printer<Tuple,  1> 
  22.   static void log(Tuple& t) { 
  23.     using type = typename std::tuple_element<0, Tuple>::type; 
  24.     std::string ts = typeid(type).name(); 
  25.     type& v = std::get<0>(t); 
  26.   
  27.     std::cout << ts << ":" << v << std::endl; 
  28.   } 
  29. }; 
  30.   
  31. int main() { 
  32.   std::tuple<int, bool, string> t = std::forward_as_tuple(11, true"ok"); 
  33.   Printer<std::tuple<int, bool, string>>::log(t); 
  34.   
  35.   return 1; 

tuple做返回相关作用

使用tuple返回多个值,tuple的一个常见用途就是从一个函数返回多个值。

返回tuple的函数

  1. tuple<int, string> fun() 
  2.         // 用make_tuple来构造一个tuple 
  3. return make_tuple(1024, "tuple"'3'); 

使用函数返回的tuple

  1. auto tp = fun(); 
  2. auto id      = std::get<0>(tp); 
  3.  
  4. auto name= std::get<1>(tp); 
  5.  
  6. auto num  = std::get<2>(tp); 

 

 本文转载自微信公众号「羽林君」,可以通过以下二维码关注。转载本文请联系羽林君公众号。

 

责任编辑:武晓燕 来源: 良知犹存
相关推荐

2021-04-19 09:23:26

数字化

2018-03-12 10:35:01

LinuxBash快捷键

2017-11-24 08:00:55

前端JSCSS

2020-06-08 15:06:33

Pandas可视化数据

2018-01-19 10:37:00

2020-04-16 09:35:53

数据科学机器学习数据分析

2010-01-26 17:35:09

C++栈

2010-02-02 09:32:32

C++ typedef

2020-08-04 07:02:00

TCPIP算法

2010-01-25 14:10:21

C++堆栈

2010-02-02 09:49:02

C++模板

2011-07-13 11:34:58

CC++时间函数

2018-03-06 09:54:48

数据库备份恢复

2018-05-02 15:41:27

JavaScript人脸检测图像识别

2022-11-28 07:32:46

迭代器remove数据库

2019-12-11 16:36:09

编程语言排行榜Python

2020-12-25 10:35:42

编程语言C语言Java

2018-04-18 17:08:45

2022-05-12 15:17:09

GPU微软神经网络

2018-01-30 17:54:37

数据库MySQLSQL Server
点赞
收藏

51CTO技术栈公众号