blob: 43d03e6558c082d468cc7d25af04a613eea0e4ee [file] [log] [blame]
Brian Silverman6bda0e12018-08-04 23:57:02 -07001[/
2 / Copyright (c) 2001 Jaakko Jรคrvi
3 /
4 / Distributed under the Boost Software License, Version 1.0. (See
5 / accompanying file LICENSE_1_0.txt or copy at
6 / http://www.boost.org/LICENSE_1_0.txt)
7 /]
8
9[library Boost.Tuple
10 [quickbook 1.6]
11 [id tuple]
12 [copyright 2001 Jaakko J\u00E4rvi]
13 [dirname tuple]
14 [license Distributed under the
15 [@http://boost.org/LICENSE_1_0.txt Boost Software License,
16 Version 1.0].
17 ]
18]
19
20[include tuple_advanced_interface.qbk]
21[include design_decisions_rationale.qbk]
22
23[template simplesect[title]
24[block '''<simplesect><title>'''[title]'''</title>''']]
25
26[template endsimplesect[]
27[block '''</simplesect>''']]
28
29A tuple (or n-tuple) is a fixed size collection of elements. Pairs, triples,
30quadruples etc. are tuples. In a programming language, a tuple is a data
31object containing other objects as elements. These element objects may be of
32different types.
33
34Tuples are convenient in many circumstances. For instance, tuples make it easy
35to define functions that return more than one value.
36
37Some programming languages, such as ML, Python and Haskell, have built-in
38tuple constructs. Unfortunately C++ does not. To compensate for this
39"deficiency", the Boost Tuple Library implements a tuple construct using
40templates.
41
42[section:using_library Using the Library]
43
44To use the library, just include:
45
46 #include "boost/tuple/tuple.hpp"
47
48Comparison operators can be included with:
49
50 #include "boost/tuple/tuple_comparison.hpp"
51
52To use tuple input and output operators,
53
54 #include "boost/tuple/tuple_io.hpp"
55
56Both `tuple_io.hpp` and `tuple_comparison.hpp` include `tuple.hpp`.
57
58All definitions are in namespace `::boost::tuples`, but the most common names
59are lifted to namespace `::boost` with using declarations. These names are:
60`tuple`, `make_tuple`, `tie` and `get`. Further, `ref` and `cref` are defined
61directly under the `::boost` namespace.
62
63[endsect]
64
65[section:tuple_types Tuple Types]
66
67A tuple type is an instantiation of the `tuple` template. The template
68parameters specify the types of the tuple elements. The current version
69supports tuples with 0-10 elements. If necessary, the upper limit can be
70increased up to, say, a few dozen elements. The data element can be any C++
71type. Note that `void` and plain function types are valid C++ types, but
72objects of such types cannot exist. Hence, if a tuple type contains such types
73as elements, the tuple type can exist, but not an object of that type. There
74are natural limitations for element types that cannot be copied, or that are
75not default constructible (see [link tuple.constructing_tuples 'Constructing tuples']
76below).
77
78For example, the following definitions are valid tuple instantiations (`A`,
79`B` and `C` are some user defined classes):
80
81 tuple<int>
82 tuple<double&, const double&, const double, double*, const double*>
83 tuple<A, int(*)(char, int), B(A::*)(C&), C>
84 tuple<std::string, std::pair<A, B> >
85 tuple<A*, tuple<const A*, const B&, C>, bool, void*>
86
87[endsect]
88
89[section:constructing_tuples Constructing Tuples]
90
91The tuple constructor takes the tuple elements as arguments. For an /n/-
92element tuple, the constructor can be invoked with /k/ arguments, where
93`0` <= /k/ <= /n/. For example:
94
95 tuple<int, double>()
96 tuple<int, double>(1)
97 tuple<int, double>(1, 3.14)
98
99If no initial value for an element is provided, it is default initialized
100(and hence must be default initializable). For example:
101
102 class X {
103 X();
104 public:
105 X(std::string);
106 };
107
108 tuple<X,X,X>() // error: no default constructor for X
109 tuple<X,X,X>(string("Jaba"), string("Daba"), string("Duu")) // ok
110
111In particular, reference types do not have a default initialization:
112
113 tuple<double&>() // error: reference must be
114 // initialized explicitly
115
116 double d = 5;
117 tuple<double&>(d) // ok
118
119 tuple<double&>(d+3.14) // error: cannot initialize
120 // non-const reference with a temporary
121
122 tuple<const double&>(d+3.14) // ok, but dangerous:
123 // the element becomes a dangling reference
124
125Using an initial value for an element that cannot be copied, is a compile time
126error:
127
128 class Y {
129 Y(const Y&);
130 public:
131 Y();
132 };
133
134 char a[10];
135
136 tuple<char[10], Y>(a, Y()); // error, neither arrays nor Y can be copied
137 tuple<char[10], Y>(); // ok
138
139Note particularly that the following is perfectly ok:
140
141 Y y;
142 tuple<char(&)[10], Y&>(a, y);
143
144It is possible to come up with a tuple type that cannot be constructed. This
145occurs if an element that cannot be initialized has a lower index than an
146element that requires initialization. For example: `tuple<char[10], int&>`.
147
148In sum, the tuple construction is semantically just a group of individual
149elementary constructions.
150
151[section:make_tuple The `make_tuple` function]
152
153Tuples can also be constructed using the `make_tuple` (cf. `std::make_pair`)
154helper functions. This makes the construction more convenient, saving the
155programmer from explicitly specifying the element types:
156
157 tuple<int, int, double> add_multiply_divide(int a, int b) {
158 return make_tuple(a+b, a*b, double(a)/double(b));
159 }
160
161By default, the element types are deduced to the plain non-reference types.
162E.g.:
163
164 void foo(const A& a, B& b) {
165 ...
166 make_tuple(a, b);
167
168The `make_tuple` invocation results in a tuple of type `tuple<A, B>`.
169
170Sometimes the plain non-reference type is not desired, e.g. if the element
171type cannot be copied. Therefore, the programmer can control the type
172deduction and state that a reference to const or reference to non-const type
173should be used as the element type instead. This is accomplished with two
174helper template functions: [@boost:/libs/core/doc/html/core/ref.html `boost::ref`]
175and [@boost:/libs/core/doc/html/core/ref.html `boost::cref`]. Any argument can
176be wrapped with these functions to get the desired type. The mechanism does
177not compromise const correctness since a const object wrapped with ref results
178in a tuple element with const reference type (see the fifth example below).
179For example:
180
181 A a; B b; const A ca = a;
182 make_tuple(cref(a), b); // creates tuple<const A&, B>
183 make_tuple(ref(a), b); // creates tuple<A&, B>
184 make_tuple(ref(a), cref(b)); // creates tuple<A&, const B&>
185 make_tuple(cref(ca)); // creates tuple<const A&>
186 make_tuple(ref(ca)); // creates tuple<const A&>
187
188Array arguments to `make_tuple` functions are deduced to reference to const
189types by default; there is no need to wrap them with `cref`. For example:
190
191 make_tuple("Donald", "Daisy");
192
193This creates an object of type `tuple<const char (&)[7], const char (&)[6]>`
194(note that the type of a string literal is an array of const characters, not
195`const char*`). However, to get `make_tuple` to create a tuple with an element
196of a non-const array type one must use the `ref` wrapper.
197
198Function pointers are deduced to the plain non-reference type, that is, to
199plain function pointer. A tuple can also hold a reference to a function, but
200such a tuple cannot be constructed with `make_tuple` (a const qualified
201function type would result, which is illegal):
202
203 void f(int i);
204 ...
205 make_tuple(&f); // tuple<void (*)(int)>
206 ...
207 tuple<tuple<void (&)(int)> > a(f) // ok
208 make_tuple(f); // not ok
209
210[endsect]
211
212[endsect]
213
214[section:accessing_elements Accessing Tuple Elements]
215
216Tuple elements are accessed with the expression:
217
218 t.get<N>()
219
220or
221
222 get<N>(t)
223
224where `t` is a tuple object and `N` is a constant integral expression
225specifying the index of the element to be accessed. Depending on whether `t`
226is const or not, `get` returns the `N`-th element as a reference to const or
227non-const type. The index of the first element is `0` and thus `N` must be
228between `0` and /k/`-1`, where /k/ is the number of elements in the tuple.
229Violations of these constraints are detected at compile time. Examples:
230
231 double d = 2.7; A a;
232 tuple<int, double&, const A&> t(1, d, a);
233 const tuple<int, double&, const A&> ct = t;
234 ...
235 int i = get<0>(t); i = t.get<0>(); // ok
236 int j = get<0>(ct); // ok
237 get<0>(t) = 5; // ok
238 get<0>(ct) = 5; // error, can't assign to const
239 ...
240 double e = get<1>(t); // ok
241 get<1>(t) = 3.14; // ok
242 get<2>(t) = A(); // error, can't assign to const
243 A aa = get<3>(t); // error: index out of bounds
244 ...
245 ++get<0>(t); // ok, can be used as any variable
246
247/[Note:/ The member `get` functions are not supported with MS Visual C++
248compiler. Further, the compiler has trouble with finding the non-member `get`
249functions without an explicit namespace qualifier. Hence, all `get` calls
250should be qualified as `tuples::get<N>(a_tuple)` when writing code that should
251compile with MSVC++ 6.0./]/
252
253[endsect]
254
255[section:construction_and_assignment Copy Construction and Tuple Assignment]
256
257A tuple can be copy constructed from another tuple, provided that the element
258types are element-wise copy constructible. Analogously, a tuple can be
259assigned to another tuple, provided that the element types are element-wise
260assignable. For example:
261
262 class A {};
263 class B : public A {};
264 struct C { C(); C(const B&); };
265 struct D { operator C() const; };
266 tuple<char, B*, B, D> t;
267 ...
268 tuple<int, A*, C, C> a(t); // ok
269 a = t; // ok
270
271In both cases, the conversions performed are:
272
273* `char -> int`,
274* `B* -> A*` (derived class pointer to base class pointer),
275* `B -> C` (a user defined conversion), and
276* `D -> C` (a user defined conversion).
277
278Note that assignment is also defined from `std::pair` types:
279
280 tuple<float, int> a = std::make_pair(1, 'a');
281
282[endsect]
283
284[section:relational_operators Relational Operators]
285
286Tuples reduce the operators `==`, `!=`, `<`, `>`, `<=` and `>=` to the
287corresponding elementary operators. This means, that if any of these operators
288is defined between all elements of two tuples, then the same operator is
289defined between the tuples as well. The equality operators for two tuples `a`
290and `b` are defined as:
291
292* `a == b` iff for each `i`: `a`'''<subscript>i</subscript>'''` == b`'''<subscript>i</subscript>'''
293* `a != b` iff exists `i`: `a`'''<subscript>i</subscript>'''` != b`'''<subscript>i</subscript>'''
294
295The operators `<`, `>`, `<=` and `>=` implement a lexicographical ordering.
296
297Note that an attempt to compare two tuples of different lengths results in a
298compile time error. Also, the comparison operators are /"short-circuited"/:
299elementary comparisons start from the first elements and are performed only
300until the result is clear.
301
302Examples:
303
304 tuple<std::string, int, A> t1(std::string("same?"), 2, A());
305 tuple<std::string, long, A> t2(std::string("same?"), 2, A());
306 tuple<std::string, long, A> t3(std::string("different"), 3, A());
307
308 bool operator==(A, A) { std::cout << "All the same to me..."; return true; }
309
310 t1 == t2; // true
311 t1 == t3; // false, does not print "All the..."
312
313[endsect]
314
315[section:tiers Tiers]
316
317/Tiers/ are tuples, where all elements are of non-const reference types. They
318are constructed with a call to the `tie` function template (cf. `make_tuple`):
319
320 int i; char c; double d;
321 ...
322 tie(i, c, a);
323
324The above `tie` function creates a tuple of type `tuple<int&, char&, double&>`.
325The same result could be achieved with the call `make_tuple(ref(i), ref(c), ref(a))`.
326
327A tuple that contains non-const references as elements can be used to 'unpack'
328another tuple into variables. E.g.:
329
330 int i; char c; double d;
331 tie(i, c, d) = make_tuple(1,'a', 5.5);
332 std::cout << i << " " << c << " " << d;
333
334This code prints `1 a 5.5` to the standard output stream. A tuple unpacking
335operation like this is found for example in ML and Python. It is convenient
336when calling functions which return tuples.
337
338The tying mechanism works with `std::pair` templates as well:
339
340 int i; char c;
341 tie(i, c) = std::make_pair(1, 'a');
342
343[section Ignore]
344
345There is also an object called `ignore` which allows you to ignore an element
346assigned by a tuple. The idea is that a function may return a tuple, only part
347of which you are interested in. For example (note, that ignore is under the
348`tuples` subnamespace):
349
350 char c;
351 tie(tuples::ignore, c) = std::make_pair(1, 'a');
352
353[endsect]
354
355[endsect]
356
357[section:streaming Streaming]
358
359The global `operator<<` has been overloaded for `std::ostream` such that
360tuples are output by recursively calling `operator<<` for each element.
361
362Analogously, the global `operator>>` has been overloaded to extract tuples
363from `std::istream` by recursively calling `operator>>` for each element.
364
365The default delimiter between the elements is space, and the tuple is enclosed
366in parenthesis. For Example:
367
368 tuple<float, int, std::string> a(1.0f, 2, std::string("Howdy folks!");
369
370 cout << a;
371
372outputs the tuple as: `(1.0 2 Howdy folks!)`
373
374The library defines three manipulators for changing the default behavior:
375
376* `set_open(char)` defines the character that is output before the first element.
377* `set_close(char)` defines the character that is output after the last element.
378* `set_delimiter(char)` defines the delimiter character between elements.
379
380Note, that these manipulators are defined in the tuples subnamespace. For
381example:
382
383 cout << tuples::set_open('[') << tuples::set_close(']') << tuples::set_delimiter(',') << a;
384
385outputs the same tuple `a` as: `[1.0,2,Howdy folks!]`
386
387The same manipulators work with `operator>>` and `istream` as well. Suppose
388the `cin` stream contains the following data:
389
390 (1 2 3) [4:5]
391
392The code:
393
394 tuple<int, int, int> i;
395 tuple<int, int> j;
396
397 cin >> i;
398 cin >> tuples::set_open('[') >> tuples::set_close(']') >> tuples::set_delimiter(':');
399 cin >> j;
400
401reads the data into the tuples `i` and `j`.
402
403Note that extracting tuples with `std::string` or C-style string elements does
404not generally work, since the streamed tuple representation may not be
405unambiguously parseable.
406
407[endsect]
408
409[section:performance Performance]
410
411All tuple access and construction functions are small inlined one-liners.
412Therefore, a decent compiler can eliminate any extra cost of using tuples
413compared to using hand-written tuple like classes. Particularly, with a decent
414compiler there is no performance difference between this code:
415
416 class hand_made_tuple {
417 A a; B b; C c;
418 public:
419 hand_made_tuple(const A& aa, const B& bb, const C& cc)
420 : a(aa), b(bb), c(cc) {};
421 A& getA() { return a; };
422 B& getB() { return b; };
423 C& getC() { return c; };
424 };
425
426 hand_made_tuple hmt(A(), B(), C());
427 hmt.getA(); hmt.getB(); hmt.getC();
428
429and this code:
430
431 tuple<A, B, C> t(A(), B(), C());
432 t.get<0>(); t.get<1>(); t.get<2>();
433
434Note, that there are widely used compilers (e.g. bcc 5.5.1) which fail to
435optimize this kind of tuple usage.
436
437Depending on the optimizing ability of the compiler, the tier mechanism may
438have a small performance penalty compared to using non-const reference
439parameters as a mechanism for returning multiple values from a function. For
440example, suppose that the following functions `f1` and `f2` have equivalent
441functionalities:
442
443 void f1(int&, double&);
444 tuple<int, double> f2();
445
446Then, the call #1 may be slightly faster than #2 in the code below:
447
448 int i; double d;
449 ...
450 f1(i,d); // #1
451 tie(i,d) = f2(); // #2
452
453See [[link publ_1 1], [link publ_2 2]] for more in-depth discussions about
454efficiency.
455
456[section Effect on Compile Time]
457
458Compiling tuples can be slow due to the excessive amount of template
459instantiations. Depending on the compiler and the tuple length, it may be more
460than 10 times slower to compile a tuple construct, compared to compiling an
461equivalent explicitly written class, such as the `hand_made_tuple` class above.
462However, as a realistic program is likely to contain a lot of code in addition
463to tuple definitions, the difference is probably unnoticeable. Compile time
464increases between 5 and 10 percent were measured for programs which used tuples
465very frequently. With the same test programs, memory consumption of compiling
466increased between 22% to 27%. See [[link publ_1 1], [link publ_2 2]] for
467details.
468
469[endsect]
470
471[endsect]
472
473[section:portability Portability]
474
475The library code is(?) standard C++ and thus the library works with a standard
476conforming compiler. Below is a list of compilers and known problems with each
477compiler:
478
479[table
480 [[Compiler] [Problems]]
481 [[gcc 2.95] [-]]
482 [[edg 2.44] [-]]
483 [[Borland 5.5] [Can't use function pointers or member pointers as
484 tuple elements]]
485 [[Metrowerks 6.2] [Can't use `ref` and `cref` wrappers]]
486 [[MS Visual C++] [No reference elements (`tie` still works). Can't use
487 `ref` and `cref` wrappers]]
488]
489
490[endsect]
491
492[section:more_details More Details]
493
494[link tuple_advanced_interface Advanced features] (describes some metafunctions etc.).
495
496[link design_decisions_rationale Rationale behind some design/implementation decisions].
497
498[endsect]
499
500[section:thanks Acknowledgements]
501
502Gary Powell has been an indispensable helping hand. In particular, stream
503manipulators for tuples were his idea. Doug Gregor came up with a working
504version for MSVC, David Abrahams found a way to get rid of most of the
505restrictions for compilers not supporting partial specialization. Thanks to
506Jeremy Siek, William Kempf and Jens Maurer for their help and suggestions. The
507comments by Vesa Karvonen, John Max Skaller, Ed Brey, Beman Dawes, David
508Abrahams and Hartmut Kaiser helped to improve the library. The idea for the
509`tie` mechanism came from an old usenet article by Ian McCulloch, where he
510proposed something similar for `std::pair`s.
511
512[endsect]
513
514[section:references References]
515
516[#publ_1]
517[1] J\u00E4rvi J.: /Tuples and multiple return values in C++/, TUCS Technical Report No 249, 1999.
518
519[#publ_2]
520[2] J\u00E4rvi J.: /ML-Style Tuple Assignment in Standard C++ - Extending the Multiple Return Value Formalism/, TUCS Technical Report No 267, 1999.
521
522[#publ_3]
523[3] J\u00E4rvi J.: /Tuple Types and Multiple Return Values/, C/C++ Users Journal, August 2001.
524
525[endsect]