123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525 |
- [/
- / Copyright (c) 2001 Jaakko Järvi
- /
- / Distributed under the Boost Software License, Version 1.0. (See
- / accompanying file LICENSE_1_0.txt or copy at
- / http://www.boost.org/LICENSE_1_0.txt)
- /]
- [library Boost.Tuple
- [quickbook 1.6]
- [id tuple]
- [copyright 2001 Jaakko J\u00E4rvi]
- [dirname tuple]
- [license Distributed under the
- [@http://boost.org/LICENSE_1_0.txt Boost Software License,
- Version 1.0].
- ]
- ]
- [include tuple_advanced_interface.qbk]
- [include design_decisions_rationale.qbk]
- [template simplesect[title]
- [block '''<simplesect><title>'''[title]'''</title>''']]
- [template endsimplesect[]
- [block '''</simplesect>''']]
- A tuple (or n-tuple) is a fixed size collection of elements. Pairs, triples,
- quadruples etc. are tuples. In a programming language, a tuple is a data
- object containing other objects as elements. These element objects may be of
- different types.
- Tuples are convenient in many circumstances. For instance, tuples make it easy
- to define functions that return more than one value.
- Some programming languages, such as ML, Python and Haskell, have built-in
- tuple constructs. Unfortunately C++ does not. To compensate for this
- "deficiency", the Boost Tuple Library implements a tuple construct using
- templates.
- [section:using_library Using the Library]
- To use the library, just include:
- #include "boost/tuple/tuple.hpp"
- Comparison operators can be included with:
- #include "boost/tuple/tuple_comparison.hpp"
- To use tuple input and output operators,
- #include "boost/tuple/tuple_io.hpp"
- Both `tuple_io.hpp` and `tuple_comparison.hpp` include `tuple.hpp`.
- All definitions are in namespace `::boost::tuples`, but the most common names
- are lifted to namespace `::boost` with using declarations. These names are:
- `tuple`, `make_tuple`, `tie` and `get`. Further, `ref` and `cref` are defined
- directly under the `::boost` namespace.
- [endsect]
- [section:tuple_types Tuple Types]
- A tuple type is an instantiation of the `tuple` template. The template
- parameters specify the types of the tuple elements. The current version
- supports tuples with 0-10 elements. If necessary, the upper limit can be
- increased up to, say, a few dozen elements. The data element can be any C++
- type. Note that `void` and plain function types are valid C++ types, but
- objects of such types cannot exist. Hence, if a tuple type contains such types
- as elements, the tuple type can exist, but not an object of that type. There
- are natural limitations for element types that cannot be copied, or that are
- not default constructible (see [link tuple.constructing_tuples 'Constructing tuples']
- below).
- For example, the following definitions are valid tuple instantiations (`A`,
- `B` and `C` are some user defined classes):
- tuple<int>
- tuple<double&, const double&, const double, double*, const double*>
- tuple<A, int(*)(char, int), B(A::*)(C&), C>
- tuple<std::string, std::pair<A, B> >
- tuple<A*, tuple<const A*, const B&, C>, bool, void*>
- [endsect]
- [section:constructing_tuples Constructing Tuples]
- The tuple constructor takes the tuple elements as arguments. For an /n/-
- element tuple, the constructor can be invoked with /k/ arguments, where
- `0` <= /k/ <= /n/. For example:
- tuple<int, double>()
- tuple<int, double>(1)
- tuple<int, double>(1, 3.14)
- If no initial value for an element is provided, it is default initialized
- (and hence must be default initializable). For example:
- class X {
- X();
- public:
- X(std::string);
- };
- tuple<X,X,X>() // error: no default constructor for X
- tuple<X,X,X>(string("Jaba"), string("Daba"), string("Duu")) // ok
- In particular, reference types do not have a default initialization:
- tuple<double&>() // error: reference must be
- // initialized explicitly
- double d = 5;
- tuple<double&>(d) // ok
- tuple<double&>(d+3.14) // error: cannot initialize
- // non-const reference with a temporary
- tuple<const double&>(d+3.14) // ok, but dangerous:
- // the element becomes a dangling reference
- Using an initial value for an element that cannot be copied, is a compile time
- error:
- class Y {
- Y(const Y&);
- public:
- Y();
- };
- char a[10];
- tuple<char[10], Y>(a, Y()); // error, neither arrays nor Y can be copied
- tuple<char[10], Y>(); // ok
- Note particularly that the following is perfectly ok:
- Y y;
- tuple<char(&)[10], Y&>(a, y);
- It is possible to come up with a tuple type that cannot be constructed. This
- occurs if an element that cannot be initialized has a lower index than an
- element that requires initialization. For example: `tuple<char[10], int&>`.
- In sum, the tuple construction is semantically just a group of individual
- elementary constructions.
- [section:make_tuple The `make_tuple` function]
- Tuples can also be constructed using the `make_tuple` (cf. `std::make_pair`)
- helper functions. This makes the construction more convenient, saving the
- programmer from explicitly specifying the element types:
- tuple<int, int, double> add_multiply_divide(int a, int b) {
- return make_tuple(a+b, a*b, double(a)/double(b));
- }
- By default, the element types are deduced to the plain non-reference types.
- E.g.:
- void foo(const A& a, B& b) {
- ...
- make_tuple(a, b);
- The `make_tuple` invocation results in a tuple of type `tuple<A, B>`.
- Sometimes the plain non-reference type is not desired, e.g. if the element
- type cannot be copied. Therefore, the programmer can control the type
- deduction and state that a reference to const or reference to non-const type
- should be used as the element type instead. This is accomplished with two
- helper template functions: [@boost:/libs/core/doc/html/core/ref.html `boost::ref`]
- and [@boost:/libs/core/doc/html/core/ref.html `boost::cref`]. Any argument can
- be wrapped with these functions to get the desired type. The mechanism does
- not compromise const correctness since a const object wrapped with ref results
- in a tuple element with const reference type (see the fifth example below).
- For example:
- A a; B b; const A ca = a;
- make_tuple(cref(a), b); // creates tuple<const A&, B>
- make_tuple(ref(a), b); // creates tuple<A&, B>
- make_tuple(ref(a), cref(b)); // creates tuple<A&, const B&>
- make_tuple(cref(ca)); // creates tuple<const A&>
- make_tuple(ref(ca)); // creates tuple<const A&>
- Array arguments to `make_tuple` functions are deduced to reference to const
- types by default; there is no need to wrap them with `cref`. For example:
- make_tuple("Donald", "Daisy");
- This creates an object of type `tuple<const char (&)[7], const char (&)[6]>`
- (note that the type of a string literal is an array of const characters, not
- `const char*`). However, to get `make_tuple` to create a tuple with an element
- of a non-const array type one must use the `ref` wrapper.
- Function pointers are deduced to the plain non-reference type, that is, to
- plain function pointer. A tuple can also hold a reference to a function, but
- such a tuple cannot be constructed with `make_tuple` (a const qualified
- function type would result, which is illegal):
- void f(int i);
- ...
- make_tuple(&f); // tuple<void (*)(int)>
- ...
- tuple<tuple<void (&)(int)> > a(f) // ok
- make_tuple(f); // not ok
- [endsect]
- [endsect]
- [section:accessing_elements Accessing Tuple Elements]
- Tuple elements are accessed with the expression:
- t.get<N>()
- or
- get<N>(t)
- where `t` is a tuple object and `N` is a constant integral expression
- specifying the index of the element to be accessed. Depending on whether `t`
- is const or not, `get` returns the `N`-th element as a reference to const or
- non-const type. The index of the first element is `0` and thus `N` must be
- between `0` and /k/`-1`, where /k/ is the number of elements in the tuple.
- Violations of these constraints are detected at compile time. Examples:
- double d = 2.7; A a;
- tuple<int, double&, const A&> t(1, d, a);
- const tuple<int, double&, const A&> ct = t;
- ...
- int i = get<0>(t); i = t.get<0>(); // ok
- int j = get<0>(ct); // ok
- get<0>(t) = 5; // ok
- get<0>(ct) = 5; // error, can't assign to const
- ...
- double e = get<1>(t); // ok
- get<1>(t) = 3.14; // ok
- get<2>(t) = A(); // error, can't assign to const
- A aa = get<3>(t); // error: index out of bounds
- ...
- ++get<0>(t); // ok, can be used as any variable
- /[Note:/ The member `get` functions are not supported with MS Visual C++
- compiler. Further, the compiler has trouble with finding the non-member `get`
- functions without an explicit namespace qualifier. Hence, all `get` calls
- should be qualified as `tuples::get<N>(a_tuple)` when writing code that should
- compile with MSVC++ 6.0./]/
- [endsect]
- [section:construction_and_assignment Copy Construction and Tuple Assignment]
- A tuple can be copy constructed from another tuple, provided that the element
- types are element-wise copy constructible. Analogously, a tuple can be
- assigned to another tuple, provided that the element types are element-wise
- assignable. For example:
- class A {};
- class B : public A {};
- struct C { C(); C(const B&); };
- struct D { operator C() const; };
- tuple<char, B*, B, D> t;
- ...
- tuple<int, A*, C, C> a(t); // ok
- a = t; // ok
- In both cases, the conversions performed are:
- * `char -> int`,
- * `B* -> A*` (derived class pointer to base class pointer),
- * `B -> C` (a user defined conversion), and
- * `D -> C` (a user defined conversion).
- Note that assignment is also defined from `std::pair` types:
- tuple<float, int> a = std::make_pair(1, 'a');
- [endsect]
- [section:relational_operators Relational Operators]
- Tuples reduce the operators `==`, `!=`, `<`, `>`, `<=` and `>=` to the
- corresponding elementary operators. This means, that if any of these operators
- is defined between all elements of two tuples, then the same operator is
- defined between the tuples as well. The equality operators for two tuples `a`
- and `b` are defined as:
- * `a == b` iff for each `i`: `a`'''<subscript>i</subscript>'''` == b`'''<subscript>i</subscript>'''
- * `a != b` iff exists `i`: `a`'''<subscript>i</subscript>'''` != b`'''<subscript>i</subscript>'''
- The operators `<`, `>`, `<=` and `>=` implement a lexicographical ordering.
- Note that an attempt to compare two tuples of different lengths results in a
- compile time error. Also, the comparison operators are /"short-circuited"/:
- elementary comparisons start from the first elements and are performed only
- until the result is clear.
- Examples:
- tuple<std::string, int, A> t1(std::string("same?"), 2, A());
- tuple<std::string, long, A> t2(std::string("same?"), 2, A());
- tuple<std::string, long, A> t3(std::string("different"), 3, A());
- bool operator==(A, A) { std::cout << "All the same to me..."; return true; }
- t1 == t2; // true
- t1 == t3; // false, does not print "All the..."
- [endsect]
- [section:tiers Tiers]
- /Tiers/ are tuples, where all elements are of non-const reference types. They
- are constructed with a call to the `tie` function template (cf. `make_tuple`):
- int i; char c; double d;
- ...
- tie(i, c, a);
- The above `tie` function creates a tuple of type `tuple<int&, char&, double&>`.
- The same result could be achieved with the call `make_tuple(ref(i), ref(c), ref(a))`.
- A tuple that contains non-const references as elements can be used to 'unpack'
- another tuple into variables. E.g.:
- int i; char c; double d;
- tie(i, c, d) = make_tuple(1,'a', 5.5);
- std::cout << i << " " << c << " " << d;
- This code prints `1 a 5.5` to the standard output stream. A tuple unpacking
- operation like this is found for example in ML and Python. It is convenient
- when calling functions which return tuples.
- The tying mechanism works with `std::pair` templates as well:
- int i; char c;
- tie(i, c) = std::make_pair(1, 'a');
- [section Ignore]
- There is also an object called `ignore` which allows you to ignore an element
- assigned by a tuple. The idea is that a function may return a tuple, only part
- of which you are interested in. For example (note, that ignore is under the
- `tuples` subnamespace):
- char c;
- tie(tuples::ignore, c) = std::make_pair(1, 'a');
- [endsect]
- [endsect]
- [section:streaming Streaming]
- The global `operator<<` has been overloaded for `std::ostream` such that
- tuples are output by recursively calling `operator<<` for each element.
- Analogously, the global `operator>>` has been overloaded to extract tuples
- from `std::istream` by recursively calling `operator>>` for each element.
- The default delimiter between the elements is space, and the tuple is enclosed
- in parenthesis. For Example:
- tuple<float, int, std::string> a(1.0f, 2, std::string("Howdy folks!");
- cout << a;
- outputs the tuple as: `(1.0 2 Howdy folks!)`
- The library defines three manipulators for changing the default behavior:
- * `set_open(char)` defines the character that is output before the first element.
- * `set_close(char)` defines the character that is output after the last element.
- * `set_delimiter(char)` defines the delimiter character between elements.
- Note, that these manipulators are defined in the tuples subnamespace. For
- example:
- cout << tuples::set_open('[') << tuples::set_close(']') << tuples::set_delimiter(',') << a;
- outputs the same tuple `a` as: `[1.0,2,Howdy folks!]`
- The same manipulators work with `operator>>` and `istream` as well. Suppose
- the `cin` stream contains the following data:
- (1 2 3) [4:5]
- The code:
- tuple<int, int, int> i;
- tuple<int, int> j;
- cin >> i;
- cin >> tuples::set_open('[') >> tuples::set_close(']') >> tuples::set_delimiter(':');
- cin >> j;
- reads the data into the tuples `i` and `j`.
- Note that extracting tuples with `std::string` or C-style string elements does
- not generally work, since the streamed tuple representation may not be
- unambiguously parseable.
- [endsect]
- [section:performance Performance]
- All tuple access and construction functions are small inlined one-liners.
- Therefore, a decent compiler can eliminate any extra cost of using tuples
- compared to using hand-written tuple like classes. Particularly, with a decent
- compiler there is no performance difference between this code:
- class hand_made_tuple {
- A a; B b; C c;
- public:
- hand_made_tuple(const A& aa, const B& bb, const C& cc)
- : a(aa), b(bb), c(cc) {};
- A& getA() { return a; };
- B& getB() { return b; };
- C& getC() { return c; };
- };
- hand_made_tuple hmt(A(), B(), C());
- hmt.getA(); hmt.getB(); hmt.getC();
- and this code:
- tuple<A, B, C> t(A(), B(), C());
- t.get<0>(); t.get<1>(); t.get<2>();
- Note, that there are widely used compilers (e.g. bcc 5.5.1) which fail to
- optimize this kind of tuple usage.
- Depending on the optimizing ability of the compiler, the tier mechanism may
- have a small performance penalty compared to using non-const reference
- parameters as a mechanism for returning multiple values from a function. For
- example, suppose that the following functions `f1` and `f2` have equivalent
- functionalities:
- void f1(int&, double&);
- tuple<int, double> f2();
- Then, the call #1 may be slightly faster than #2 in the code below:
- int i; double d;
- ...
- f1(i,d); // #1
- tie(i,d) = f2(); // #2
- See [[link publ_1 1], [link publ_2 2]] for more in-depth discussions about
- efficiency.
- [section Effect on Compile Time]
- Compiling tuples can be slow due to the excessive amount of template
- instantiations. Depending on the compiler and the tuple length, it may be more
- than 10 times slower to compile a tuple construct, compared to compiling an
- equivalent explicitly written class, such as the `hand_made_tuple` class above.
- However, as a realistic program is likely to contain a lot of code in addition
- to tuple definitions, the difference is probably unnoticeable. Compile time
- increases between 5 and 10 percent were measured for programs which used tuples
- very frequently. With the same test programs, memory consumption of compiling
- increased between 22% to 27%. See [[link publ_1 1], [link publ_2 2]] for
- details.
- [endsect]
- [endsect]
- [section:portability Portability]
- The library code is(?) standard C++ and thus the library works with a standard
- conforming compiler. Below is a list of compilers and known problems with each
- compiler:
- [table
- [[Compiler] [Problems]]
- [[gcc 2.95] [-]]
- [[edg 2.44] [-]]
- [[Borland 5.5] [Can't use function pointers or member pointers as
- tuple elements]]
- [[Metrowerks 6.2] [Can't use `ref` and `cref` wrappers]]
- [[MS Visual C++] [No reference elements (`tie` still works). Can't use
- `ref` and `cref` wrappers]]
- ]
- [endsect]
- [section:more_details More Details]
- [link tuple_advanced_interface Advanced features] (describes some metafunctions etc.).
- [link design_decisions_rationale Rationale behind some design/implementation decisions].
- [endsect]
- [section:thanks Acknowledgements]
- Gary Powell has been an indispensable helping hand. In particular, stream
- manipulators for tuples were his idea. Doug Gregor came up with a working
- version for MSVC, David Abrahams found a way to get rid of most of the
- restrictions for compilers not supporting partial specialization. Thanks to
- Jeremy Siek, William Kempf and Jens Maurer for their help and suggestions. The
- comments by Vesa Karvonen, John Max Skaller, Ed Brey, Beman Dawes, David
- Abrahams and Hartmut Kaiser helped to improve the library. The idea for the
- `tie` mechanism came from an old usenet article by Ian McCulloch, where he
- proposed something similar for `std::pair`s.
- [endsect]
- [section:references References]
- [#publ_1]
- [1] J\u00E4rvi J.: /Tuples and multiple return values in C++/, TUCS Technical Report No 249, 1999.
- [#publ_2]
- [2] J\u00E4rvi J.: /ML-Style Tuple Assignment in Standard C++ - Extending the Multiple Return Value Formalism/, TUCS Technical Report No 267, 1999.
- [#publ_3]
- [3] J\u00E4rvi J.: /Tuple Types and Multiple Return Values/, C/C++ Users Journal, August 2001.
- [endsect]
|