]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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 "deficiency", 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 "boost/tuple/tuple.hpp"</code></pre> | |
60 | ||
61 | <p>Comparison operators can be included with:</p> | |
62 | <pre><code>#include "boost/tuple/tuple_comparison.hpp"</code></pre> | |
63 | ||
64 | <p>To use tuple input and output operators,</p> | |
65 | ||
66 | <pre><code>#include "boost/tuple/tuple_io.hpp"</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<int> | |
93 | tuple<double&, const double&, const double, double*, const double*> | |
94 | tuple<A, int(*)(char, int), B(A::*)(C&), C> | |
95 | tuple<std::string, std::pair<A, B> > | |
96 | tuple<A*, tuple<const A*, const B&, C>, bool, void*> | |
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 <= <i>k</i> <= <i>n</i>. | |
104 | For example:</p> | |
105 | <pre><code>tuple<int, double>() | |
106 | tuple<int, double>(1) | |
107 | tuple<int, double>(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<X,X,X>() // error: no default constructor for X | |
121 | tuple<X,X,X>(string("Jaba"), string("Daba"), string("Duu")) // ok | |
122 | </code></pre> | |
123 | ||
124 | <p>In particular, reference types do not have a default initialization: </p> | |
125 | ||
126 | <pre><code>tuple<double&>() // error: reference must be | |
127 | // initialized explicitly | |
128 | ||
129 | double d = 5; | |
130 | tuple<double&>(d) // ok | |
131 | ||
132 | tuple<double&>(d+3.14) // error: cannot initialize | |
133 | // non-const reference with a temporary | |
134 | ||
135 | tuple<const double&>(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&); | |
144 | public: | |
145 | Y(); | |
146 | }; | |
147 | ||
148 | char a[10]; | |
149 | ||
150 | tuple<char[10], Y>(a, Y()); // error, neither arrays nor Y can be copied | |
151 | tuple<char[10], Y>(); // ok | |
152 | </code></pre> | |
153 | ||
154 | <p>Note particularly that the following is perfectly ok:</p> | |
155 | <pre><code>Y y; | |
156 | tuple<char(&)[10], Y&>(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<char[10], int&></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<int, int, double> 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& a, B& 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<A, B></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<const A&, B> | |
197 | make_tuple(ref(a), b); // creates tuple<A&, B> | |
198 | make_tuple(ref(a), cref(b)); // creates tuple<A&, const B&> | |
199 | make_tuple(cref(ca)); // creates tuple<const A&> | |
200 | make_tuple(ref(ca)); // creates tuple<const A&> | |
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("Donald", "Daisy"); | |
207 | </code></pre> | |
208 | ||
209 | <p>This creates an object of type <code>tuple<const char (&)[7], const char (&)[6]></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(&f); // tuple<void (*)(int)> | |
221 | ... | |
222 | tuple<tuple<void (&)(int)> > 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<N>() | |
232 | </code></pre> | |
233 | <p>or</p> | |
234 | <pre><code>get<N>(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<int, double&, const A&> t(1, d, a); | |
245 | const tuple<int, double&, const A&> ct = t; | |
246 | ... | |
247 | int i = get<0>(t); i = t.get<0>(); // ok | |
248 | int j = get<0>(ct); // ok | |
249 | get<0>(t) = 5; // ok | |
250 | get<0>(ct) = 5; // error, can't assign to const | |
251 | ... | |
252 | double e = get<1>(t); // ok | |
253 | get<1>(t) = 3.14; // ok | |
254 | get<2>(t) = A(); // error, can't assign to const | |
255 | A aa = get<3>(t); // error: index out of bounds | |
256 | ... | |
257 | ++get<0>(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<N>(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&); }; | |
276 | struct D { operator C() const; }; | |
277 | tuple<char, B*, B, D> t; | |
278 | ... | |
279 | tuple<int, A*, C, C> 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<float, int> 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>==, !=, <, >, <=</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><, >, <=</code> and <code>>=</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<std::string, int, A> t1(std::string("same?"), 2, A()); | |
311 | tuple<std::string, long, A> t2(std::string("same?"), 2, A()); | |
312 | tuple<std::string, long, A> t3(std::string("different"), 3, A()); | |
313 | ||
314 | bool operator==(A, A) { std::cout << "All the same to me..."; return true; } | |
315 | ||
316 | t1 == t2; // true | |
317 | t1 == t3; // false, does not print "All the..." | |
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<int&, char&, double&></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 << i << " " << c << " " << 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<<</code> has been overloaded for <code>std::ostream</code> such that tuples are | |
367 | output by recursively calling <code>operator<<</code> for each element. | |
368 | </p> | |
369 | ||
370 | <p> | |
371 | Analogously, the global <code>operator>></code> has been overloaded to extract tuples from <code>std::istream</code> by recursively calling <code>operator>></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<float, int, std::string> a(1.0f, 2, std::string("Howdy folks!"); | |
380 | ||
381 | cout << 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 << tuples::set_open('[') << tuples::set_close(']') << tuples::set_delimiter(',') << 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>></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<int, int, int> i; | |
409 | tuple<int, int> j; | |
410 | ||
411 | cin >> i; | |
412 | cin >> tuples::set_open('[') >> tuples::set_close(']') >> tuples::set_delimiter(':'); | |
413 | cin >> 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& aa, const B& bb, const C& cc) | |
434 | : a(aa), b(bb), c(cc) {}; | |
435 | A& getA() { return a; }; | |
436 | B& getB() { return b; }; | |
437 | C& 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<A, B, C> t(A(), B(), C()); | |
447 | t.get<0>(); t.get<1>(); t.get<2>(); | |
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&, double&); | |
458 | tuple<int, double> 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ä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ä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ä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>© Copyright <a href="http://www.boost.org/people/jaakko_jarvi.htm"> Jaakko Jä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 |