std::tuple是类似pair的模板。每个pair的成员类型都不相同,但每个pair都恰好有两个成员。不同std::tuple类型的成员类型也不相同,但一个std::tuple可以有任意数量的成员。每个确定的std::tuple类型的成员数目是固定的,但一个std::tuple类型的成员数目可以与另一个std::tuple类型不同。
但我们希望将一些数据组合成单一对象,但又不想麻烦地定义一个新数据结构来表示这些数据时,std::tuple是非常有用的。我们可以将std::tuple看作一个”快速而随意”的数据结构。
当我们定义一个std::tuple时,需要指出每个成员的类型。当我们创建一个std::tuple对象时,可以使用tuple的默认构造函数,它会对每个成员进行值初始化;也可以为每个成员提供一个初始值,此时的构造函数是explicit的,因此必须使用直接初始化方法。类似make_pair函数,标准库定义了make_tuple函数,我们还可以使用它来生成std::tuple对象。类似make_pair,make_tuple函数使用初始值的类型来推断tuple的类型。
一个std::tuple类型的成员数目是没有限制的,因此,tuple的成员都是未命名的。要访问一个tuple的成员,就要使用一个名为get的标准库函数模板。为了使用get,我们必须指定一个显式模板实参,它指出我们想要访问第几个成员。我们传递给get一个tuple对象,它返回指定成员的引用。get尖括号中的值必须是一个整型常量表达式。与往常一样,我们从0开始计数,意味着get<0>是第一个成员。
为了使用tuple_size或tuple_element,我们需要知道一个tuple对象的类型。与往常一样,确定一个对象的类型的最简单方法就是使用decltype。
std::tuple的关系和相等运算符的行为类似容器的对应操作。这些运算符逐对比较左侧tuple和右侧tuple的成员。只有两个tuple具有相同数量的成员时,我们才可以比较它们。而且,为了使用tuple的相等或不等运算符,对每对成员使用==运算符必须都是合法的;为了使用关系运算符,对每对成员使用<必须都是合法的。由于tuple定义了<和==运算符,我们可以将tuple序列传递给算法,并且可以在无序容器中将tuple作为关键字类型。
std::tuple的一个常见用途是从一个函数返回多个值。
std::tuple是一个模板,允许我们将多个不同类型的成员捆绑成单一对象。每个tuple包含指定数量的成员,但对一个给定的tuple类型,标准库并未限制我们可以定义的成员数量上限。
std::tuple中元素是被紧密地存储的(位于连续的内存区域),而不是链式结构。
std::tuple实现了多元组,这是一个编译期就确定大小的容器,可以容纳不同类型的元素。多元组类型在当前标准库中被定义为可以用任意数量参数初始化的类模板。每一模板参数确定多元组中一元素的类型。所以,多元组是一个多类型、大小固定的值的集合。
下面是从其他文章中copy的测试代码,详细内容介绍可以参考对应的reference:
#include "tuple.hpp"
#include <iostream>
#include <tuple>
#include <string>
#include <functional>
#include <utility>
//////////////////////////////////////////////////////////
// reference: http://www.cplusplus.com/reference/tuple/tuple/
int test_tuple_4()
{
{ // tuple::tuple: Constructs a tuple object. This involves individually constructing its elements,
// with an initialization that depends on the constructor form invoke
std::tuple<int, char> first; // default
std::tuple<int, char> second(first); // copy
std::tuple<int, char> third(std::make_tuple(20, 'b')); // move
std::tuple<long, char> fourth(third); // implicit conversion
std::tuple<int, char> fifth(10, 'a'); // initialization
std::tuple<int, char> sixth(std::make_pair(30, 'c')); // from pair / move
std::cout << "sixth contains: " << std::get<0>(sixth);
std::cout << " and " << std::get<1>(sixth) << '\n';
}
{ // std::tuple::operator=: Each of the elements in the tuple object is assigned its corresponding element
std::pair<int, char> mypair(0, ' ');
std::tuple<int, char> a(10, 'x');
std::tuple<long, char> b, c;
b = a; // copy assignment
c = std::make_tuple(100L, 'Y'); // move assignment
a = c; // conversion assignment
c = std::make_tuple(100, 'z'); // conversion / move assignment
a = mypair; // from pair assignment
a = std::make_pair(2, 'b'); // form pair /move assignment
std::cout << "c contains: " << std::get<0>(c);
std::cout << " and " << std::get<1>(c) << '\n';
}
{ // std::tuple::swap: Exchanges the content of the tuple object by the content of tpl,
// which is another tuple of the same type (containing objects of the same types in the same order)
std::tuple<int, char> a(10, 'x');
std::tuple<int, char> b(20, 'y');
a.swap(b);
std::cout << "a contains: " << std::get<0>(a);
std::cout << " and " << std::get<1>(a) << '\n';
std::swap(a, b);
std::cout << "a contains: " << std::get<0>(a);
std::cout << " and " << std::get<1>(a) << '\n';
}
{ // std::relational operators: Performs the appropriate comparison operation between the tuple objects lhs and rhs
std::tuple<int, char> a(10, 'x');
std::tuple<char, char> b(10, 'x');
std::tuple<char, char> c(10, 'y');
if (a == b) std::cout << "a and b are equal\n";
if (b != c) std::cout << "b and c are not equal\n";
if (b<c) std::cout << "b is less than c\n";
if (c>a) std::cout << "c is greater than a\n";
if (a <= c) std::cout << "a is less than or equal to c\n";
if (c >= b) std::cout << "c is greater than or equal to b\n";
}
return 0;
}
////////////////////////////////////////////////
// reference: https://msdn.microsoft.com/en-us/library/bb982771.aspx
int test_tuple_3()
{
typedef std::tuple<int, double, int, double> Mytuple;
Mytuple c0(0, 1, 2, 3);
// display contents " 0 1 2 3"
std::cout << " " << std::get<0>(c0);
std::cout << " " << std::get<1>(c0);
std::cout << " " << std::get<2>(c0);
std::cout << " " << std::get<3>(c0);
std::cout << std::endl;
Mytuple c1;
c1 = c0;
// display contents " 0 1 2 3"
std::cout << " " << std::get<0>(c1);
std::cout << " " << std::get<1>(c1);
std::cout << " " << std::get<2>(c1);
std::cout << " " << std::get<3>(c1);
std::cout << std::endl;
std::tuple<char, int> c2(std::make_pair('x', 4));
// display contents " x 4"
std::cout << " " << std::get<0>(c2);
std::cout << " " << std::get<1>(c2);
std::cout << std::endl;
Mytuple c3(c0);
// display contents " 0 1 2 3"
std::cout << " " << std::get<0>(c3);
std::cout << " " << std::get<1>(c3);
std::cout << " " << std::get<2>(c3);
std::cout << " " << std::get<3>(c3);
std::cout << std::endl;
typedef std::tuple<int, float, int, float> Mytuple2;
Mytuple c4(Mytuple2(4, 5, 6, 7));
// display contents " 4 5 6 7"
std::cout << " " << std::get<0>(c4);
std::cout << " " << std::get<1>(c4);
std::cout << " " << std::get<2>(c4);
std::cout << " " << std::get<3>(c4);
std::cout << std::endl;
return (0);
}
///////////////////////////////////////////////////
// reference: http://zh.cppreference.com/w/cpp/utility/tuple
static std::tuple<double, char, std::string> get_student(int id)
{
if (id == 0) return std::make_tuple(3.8, 'A', "Lisa Simpson");
if (id == 1) return std::make_tuple(2.9, 'C', "Milhouse Van Houten");
if (id == 2) return std::make_tuple(1.7, 'D', "Ralph Wiggum");
throw std::invalid_argument("id");
}
int test_tuple_2()
{
auto student0 = get_student(0);
std::cout << "ID: 0, "
<< "GPA: " << std::get<0>(student0) << ", "
<< "grade: " << std::get<1>(student0) << ", "
<< "name: " << std::get<2>(student0) << '\n';
double gpa1;
char grade1;
std::string name1;
std::tie(gpa1, grade1, name1) = get_student(1);
std::cout << "ID: 1, "
<< "GPA: " << gpa1 << ", "
<< "grade: " << grade1 << ", "
<< "name: " << name1 << '\n';
return 0;
}
///////////////////////////////////////////////
// reference: http://www.cplusplus.com/reference/tuple/
static void print_pack(std::tuple<std::string&&, int&&> pack)
{
std::cout << std::get<0>(pack) << ", " << std::get<1>(pack) << '\n';
}
static void fun(int &a)
{
a = 15;
}
int test_tuple_1()
{
{ // std::tuple_element: class template, Class designed to access the type of the Ith element in a tuple.
// It is a simple class with a single member type, tuple_element::type,
// defined as an alias of the type of the Ith element in a tuple of type T.
auto mytuple = std::make_tuple(10, 'a');
std::tuple_element<0, decltype(mytuple)>::type first = std::get<0>(mytuple);
std::tuple_element<1, decltype(mytuple)>::type second = std::get<1>(mytuple);
std::cout << "mytuple contains: " << first << " and " << second << '\n';
}
{ // std::tuple_size: Class template designed to access the number of elements in a tuple
std::tuple<int, char, double> mytuple(10, 'a', 3.14);
std::cout << "mytuple has ";
std::cout << std::tuple_size<decltype(mytuple)>::value;
std::cout << " elements." << '\n';
}
{ // std::forward_as_tuple: function template, Constructs a tuple object with rvalue references
// to the elements in args suitable to be forwarded as argument to a function.
std::string str("John");
print_pack(std::forward_as_tuple(str + " Smith", 25));
print_pack(std::forward_as_tuple(str + " Daniels", 22));
}
{ // std::get: funtion template, Returns a reference to the Ith element of tuple tpl.
std::tuple<int, char> mytuple(10, 'a');
std::get<0>(mytuple) = 20;
std::cout << "mytuple contains: ";
std::cout << std::get<0>(mytuple) << " and " << std::get<1>(mytuple);
std::cout << std::endl;
}
{ // std::make_tuple: function template, Constructs an object of the appropriate tuple type
// to contain the elements specified in args
auto first = std::make_tuple(10, 'a'); // tuple < int, char >
const int a = 0; int b[3]; // decayed types:
auto second = std::make_tuple(a, b); // tuple < int, int* >
auto third = std::make_tuple(std::ref(a), "abc"); // tuple < const int&, const char* >
std::cout << "third contains: " << std::get<0>(third);
std::cout << " and " << std::get<1>(third);
std::cout << std::endl;
}
{ // std::tie: function template, Constructs a tuple object whose elements are references
// to the arguments in args, in the same order
// std::ignore: object, This object ignores any value assigned to it. It is designed to be used as an
// argument for tie to indicate that a specific element in a tuple should be ignored.
int myint;
char mychar;
std::tuple<int, float, char> mytuple;
mytuple = std::make_tuple(10, 2.6, 'a'); // packing values into tuple
std::tie(myint, std::ignore, mychar) = mytuple; // unpacking tuple into variables
std::cout << "myint contains: " << myint << '\n';
std::cout << "mychar contains: " << mychar << '\n';
}
{ // std::tuple_cat: function template, Constructs an object of the appropriate tuple type
// to contain a concatenation of the elements of all the tuples in tpls, in the same order
std::tuple<float, std::string> mytuple(3.14, "pi");
std::pair<int, char> mypair(10, 'a');
auto myauto = std::tuple_cat(mytuple, std::tuple<int, char>(mypair));
std::cout << "myauto contains: " << '\n';
std::cout << std::get<0>(myauto) << '\n';
std::cout << std::get<1>(myauto) << '\n';
std::cout << std::get<2>(myauto) << '\n';
std::cout << std::get<3>(myauto) << '\n';
}
{ // tuple::tuple: A tuple is an object capable to hold a collection of elements.
// Each element can be of a different type.
std::tuple<int, char> foo(10, 'x');
auto bar = std::make_tuple("test", 3.1, 14, 'y');
std::get<2>(bar) = 100; // access element
int myint; char mychar;
std::tie(myint, mychar) = foo; // unpack elements
std::tie(std::ignore, std::ignore, myint, mychar) = bar; // unpack (with ignore)
mychar = std::get<3>(bar);
std::get<0>(foo) = std::get<2>(bar);
std::get<1>(foo) = mychar;
std::cout << "foo contains: ";
std::cout << std::get<0>(foo) << ' ';
std::cout << std::get<1>(foo) << '\n';
}
{
std::tuple<int, char> foo{ 12, 'a' };
std::cout << std::get<0>(foo) << "\n"; // 12
fun(std::get<0>(foo));
std::cout << std::get<0>(foo) << "\n"; // 15
}
return 0;
}
GitHub: https://github.com/fengbingchun/Messy_Test