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