Brian Silverman | 6bda0e1 | 2018-08-04 23:57:02 -0700 | [diff] [blame^] | 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 | |
| 29 | A tuple (or n-tuple) is a fixed size collection of elements. Pairs, triples, |
| 30 | quadruples etc. are tuples. In a programming language, a tuple is a data |
| 31 | object containing other objects as elements. These element objects may be of |
| 32 | different types. |
| 33 | |
| 34 | Tuples are convenient in many circumstances. For instance, tuples make it easy |
| 35 | to define functions that return more than one value. |
| 36 | |
| 37 | Some programming languages, such as ML, Python and Haskell, have built-in |
| 38 | tuple constructs. Unfortunately C++ does not. To compensate for this |
| 39 | "deficiency", the Boost Tuple Library implements a tuple construct using |
| 40 | templates. |
| 41 | |
| 42 | [section:using_library Using the Library] |
| 43 | |
| 44 | To use the library, just include: |
| 45 | |
| 46 | #include "boost/tuple/tuple.hpp" |
| 47 | |
| 48 | Comparison operators can be included with: |
| 49 | |
| 50 | #include "boost/tuple/tuple_comparison.hpp" |
| 51 | |
| 52 | To use tuple input and output operators, |
| 53 | |
| 54 | #include "boost/tuple/tuple_io.hpp" |
| 55 | |
| 56 | Both `tuple_io.hpp` and `tuple_comparison.hpp` include `tuple.hpp`. |
| 57 | |
| 58 | All definitions are in namespace `::boost::tuples`, but the most common names |
| 59 | are lifted to namespace `::boost` with using declarations. These names are: |
| 60 | `tuple`, `make_tuple`, `tie` and `get`. Further, `ref` and `cref` are defined |
| 61 | directly under the `::boost` namespace. |
| 62 | |
| 63 | [endsect] |
| 64 | |
| 65 | [section:tuple_types Tuple Types] |
| 66 | |
| 67 | A tuple type is an instantiation of the `tuple` template. The template |
| 68 | parameters specify the types of the tuple elements. The current version |
| 69 | supports tuples with 0-10 elements. If necessary, the upper limit can be |
| 70 | increased up to, say, a few dozen elements. The data element can be any C++ |
| 71 | type. Note that `void` and plain function types are valid C++ types, but |
| 72 | objects of such types cannot exist. Hence, if a tuple type contains such types |
| 73 | as elements, the tuple type can exist, but not an object of that type. There |
| 74 | are natural limitations for element types that cannot be copied, or that are |
| 75 | not default constructible (see [link tuple.constructing_tuples 'Constructing tuples'] |
| 76 | below). |
| 77 | |
| 78 | For 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 | |
| 91 | The tuple constructor takes the tuple elements as arguments. For an /n/- |
| 92 | element 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 | |
| 99 | If 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 | |
| 111 | In 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 | |
| 125 | Using an initial value for an element that cannot be copied, is a compile time |
| 126 | error: |
| 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 | |
| 139 | Note particularly that the following is perfectly ok: |
| 140 | |
| 141 | Y y; |
| 142 | tuple<char(&)[10], Y&>(a, y); |
| 143 | |
| 144 | It is possible to come up with a tuple type that cannot be constructed. This |
| 145 | occurs if an element that cannot be initialized has a lower index than an |
| 146 | element that requires initialization. For example: `tuple<char[10], int&>`. |
| 147 | |
| 148 | In sum, the tuple construction is semantically just a group of individual |
| 149 | elementary constructions. |
| 150 | |
| 151 | [section:make_tuple The `make_tuple` function] |
| 152 | |
| 153 | Tuples can also be constructed using the `make_tuple` (cf. `std::make_pair`) |
| 154 | helper functions. This makes the construction more convenient, saving the |
| 155 | programmer 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 | |
| 161 | By default, the element types are deduced to the plain non-reference types. |
| 162 | E.g.: |
| 163 | |
| 164 | void foo(const A& a, B& b) { |
| 165 | ... |
| 166 | make_tuple(a, b); |
| 167 | |
| 168 | The `make_tuple` invocation results in a tuple of type `tuple<A, B>`. |
| 169 | |
| 170 | Sometimes the plain non-reference type is not desired, e.g. if the element |
| 171 | type cannot be copied. Therefore, the programmer can control the type |
| 172 | deduction and state that a reference to const or reference to non-const type |
| 173 | should be used as the element type instead. This is accomplished with two |
| 174 | helper template functions: [@boost:/libs/core/doc/html/core/ref.html `boost::ref`] |
| 175 | and [@boost:/libs/core/doc/html/core/ref.html `boost::cref`]. Any argument can |
| 176 | be wrapped with these functions to get the desired type. The mechanism does |
| 177 | not compromise const correctness since a const object wrapped with ref results |
| 178 | in a tuple element with const reference type (see the fifth example below). |
| 179 | For 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 | |
| 188 | Array arguments to `make_tuple` functions are deduced to reference to const |
| 189 | types by default; there is no need to wrap them with `cref`. For example: |
| 190 | |
| 191 | make_tuple("Donald", "Daisy"); |
| 192 | |
| 193 | This 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 |
| 196 | of a non-const array type one must use the `ref` wrapper. |
| 197 | |
| 198 | Function pointers are deduced to the plain non-reference type, that is, to |
| 199 | plain function pointer. A tuple can also hold a reference to a function, but |
| 200 | such a tuple cannot be constructed with `make_tuple` (a const qualified |
| 201 | function 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 | |
| 216 | Tuple elements are accessed with the expression: |
| 217 | |
| 218 | t.get<N>() |
| 219 | |
| 220 | or |
| 221 | |
| 222 | get<N>(t) |
| 223 | |
| 224 | where `t` is a tuple object and `N` is a constant integral expression |
| 225 | specifying the index of the element to be accessed. Depending on whether `t` |
| 226 | is const or not, `get` returns the `N`-th element as a reference to const or |
| 227 | non-const type. The index of the first element is `0` and thus `N` must be |
| 228 | between `0` and /k/`-1`, where /k/ is the number of elements in the tuple. |
| 229 | Violations 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++ |
| 248 | compiler. Further, the compiler has trouble with finding the non-member `get` |
| 249 | functions without an explicit namespace qualifier. Hence, all `get` calls |
| 250 | should be qualified as `tuples::get<N>(a_tuple)` when writing code that should |
| 251 | compile with MSVC++ 6.0./]/ |
| 252 | |
| 253 | [endsect] |
| 254 | |
| 255 | [section:construction_and_assignment Copy Construction and Tuple Assignment] |
| 256 | |
| 257 | A tuple can be copy constructed from another tuple, provided that the element |
| 258 | types are element-wise copy constructible. Analogously, a tuple can be |
| 259 | assigned to another tuple, provided that the element types are element-wise |
| 260 | assignable. 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 | |
| 271 | In 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 | |
| 278 | Note 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 | |
| 286 | Tuples reduce the operators `==`, `!=`, `<`, `>`, `<=` and `>=` to the |
| 287 | corresponding elementary operators. This means, that if any of these operators |
| 288 | is defined between all elements of two tuples, then the same operator is |
| 289 | defined between the tuples as well. The equality operators for two tuples `a` |
| 290 | and `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 | |
| 295 | The operators `<`, `>`, `<=` and `>=` implement a lexicographical ordering. |
| 296 | |
| 297 | Note that an attempt to compare two tuples of different lengths results in a |
| 298 | compile time error. Also, the comparison operators are /"short-circuited"/: |
| 299 | elementary comparisons start from the first elements and are performed only |
| 300 | until the result is clear. |
| 301 | |
| 302 | Examples: |
| 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 |
| 318 | are 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 | |
| 324 | The above `tie` function creates a tuple of type `tuple<int&, char&, double&>`. |
| 325 | The same result could be achieved with the call `make_tuple(ref(i), ref(c), ref(a))`. |
| 326 | |
| 327 | A tuple that contains non-const references as elements can be used to 'unpack' |
| 328 | another 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 | |
| 334 | This code prints `1 a 5.5` to the standard output stream. A tuple unpacking |
| 335 | operation like this is found for example in ML and Python. It is convenient |
| 336 | when calling functions which return tuples. |
| 337 | |
| 338 | The 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 | |
| 345 | There is also an object called `ignore` which allows you to ignore an element |
| 346 | assigned by a tuple. The idea is that a function may return a tuple, only part |
| 347 | of 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 | |
| 359 | The global `operator<<` has been overloaded for `std::ostream` such that |
| 360 | tuples are output by recursively calling `operator<<` for each element. |
| 361 | |
| 362 | Analogously, the global `operator>>` has been overloaded to extract tuples |
| 363 | from `std::istream` by recursively calling `operator>>` for each element. |
| 364 | |
| 365 | The default delimiter between the elements is space, and the tuple is enclosed |
| 366 | in parenthesis. For Example: |
| 367 | |
| 368 | tuple<float, int, std::string> a(1.0f, 2, std::string("Howdy folks!"); |
| 369 | |
| 370 | cout << a; |
| 371 | |
| 372 | outputs the tuple as: `(1.0 2 Howdy folks!)` |
| 373 | |
| 374 | The 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 | |
| 380 | Note, that these manipulators are defined in the tuples subnamespace. For |
| 381 | example: |
| 382 | |
| 383 | cout << tuples::set_open('[') << tuples::set_close(']') << tuples::set_delimiter(',') << a; |
| 384 | |
| 385 | outputs the same tuple `a` as: `[1.0,2,Howdy folks!]` |
| 386 | |
| 387 | The same manipulators work with `operator>>` and `istream` as well. Suppose |
| 388 | the `cin` stream contains the following data: |
| 389 | |
| 390 | (1 2 3) [4:5] |
| 391 | |
| 392 | The 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 | |
| 401 | reads the data into the tuples `i` and `j`. |
| 402 | |
| 403 | Note that extracting tuples with `std::string` or C-style string elements does |
| 404 | not generally work, since the streamed tuple representation may not be |
| 405 | unambiguously parseable. |
| 406 | |
| 407 | [endsect] |
| 408 | |
| 409 | [section:performance Performance] |
| 410 | |
| 411 | All tuple access and construction functions are small inlined one-liners. |
| 412 | Therefore, a decent compiler can eliminate any extra cost of using tuples |
| 413 | compared to using hand-written tuple like classes. Particularly, with a decent |
| 414 | compiler 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 | |
| 429 | and this code: |
| 430 | |
| 431 | tuple<A, B, C> t(A(), B(), C()); |
| 432 | t.get<0>(); t.get<1>(); t.get<2>(); |
| 433 | |
| 434 | Note, that there are widely used compilers (e.g. bcc 5.5.1) which fail to |
| 435 | optimize this kind of tuple usage. |
| 436 | |
| 437 | Depending on the optimizing ability of the compiler, the tier mechanism may |
| 438 | have a small performance penalty compared to using non-const reference |
| 439 | parameters as a mechanism for returning multiple values from a function. For |
| 440 | example, suppose that the following functions `f1` and `f2` have equivalent |
| 441 | functionalities: |
| 442 | |
| 443 | void f1(int&, double&); |
| 444 | tuple<int, double> f2(); |
| 445 | |
| 446 | Then, 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 | |
| 453 | See [[link publ_1 1], [link publ_2 2]] for more in-depth discussions about |
| 454 | efficiency. |
| 455 | |
| 456 | [section Effect on Compile Time] |
| 457 | |
| 458 | Compiling tuples can be slow due to the excessive amount of template |
| 459 | instantiations. Depending on the compiler and the tuple length, it may be more |
| 460 | than 10 times slower to compile a tuple construct, compared to compiling an |
| 461 | equivalent explicitly written class, such as the `hand_made_tuple` class above. |
| 462 | However, as a realistic program is likely to contain a lot of code in addition |
| 463 | to tuple definitions, the difference is probably unnoticeable. Compile time |
| 464 | increases between 5 and 10 percent were measured for programs which used tuples |
| 465 | very frequently. With the same test programs, memory consumption of compiling |
| 466 | increased between 22% to 27%. See [[link publ_1 1], [link publ_2 2]] for |
| 467 | details. |
| 468 | |
| 469 | [endsect] |
| 470 | |
| 471 | [endsect] |
| 472 | |
| 473 | [section:portability Portability] |
| 474 | |
| 475 | The library code is(?) standard C++ and thus the library works with a standard |
| 476 | conforming compiler. Below is a list of compilers and known problems with each |
| 477 | compiler: |
| 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 | |
| 502 | Gary Powell has been an indispensable helping hand. In particular, stream |
| 503 | manipulators for tuples were his idea. Doug Gregor came up with a working |
| 504 | version for MSVC, David Abrahams found a way to get rid of most of the |
| 505 | restrictions for compilers not supporting partial specialization. Thanks to |
| 506 | Jeremy Siek, William Kempf and Jens Maurer for their help and suggestions. The |
| 507 | comments by Vesa Karvonen, John Max Skaller, Ed Brey, Beman Dawes, David |
| 508 | Abrahams 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 |
| 510 | proposed 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] |