20220903 tuple类型
明昧 Lv7

前言

其实没有想到的是C++里面也会有跟python一样的元组

很神奇

看看用法

qt

qt中没有对应的实现

如果真的要实现还是得去std库里面去拿

C++11

https://blog.csdn.net/fengbingchun/article/details/72835446

std::tuple是类似pair的模板。每个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实现了多元组,这是一个编译期就确定大小的容器,可以容纳不同类型的元素。多元组类型在当前标准库中被定义为可以用任意数量参数初始化的类模板。每一模板参数确定多元组中一元素的类型。所以,多元组是一个多类型、大小固定的值的集合。

总结

感觉std::tuple 的实现主要依赖于C++模板和模板来实现。

能够实现类似

这样的调用和相关实现

std::tuple<int, double, std::string> myTuple(42, 3.14, “hello”);

底层机制实现方面,我感觉是

模板参数允许模板接受可变数量的类型参数 并且 实现类型推断。

tuple 的每个元素的类型和数量在编译时就已经确定的,这通过模板类型推断和继承链来实现。

参考的使用例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
#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;
}
 Comments
Comment plugin failed to load
Loading comment plugin
Powered by Hexo & Theme Keep
Unique Visitor Page View