• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1[/
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]
526