1<html> 2 <head> 3 <title>file_iteration.html</title> 4 <link rel="stylesheet" type="text/css" href="../styles.css"> 5 </head> 6 <body> 7 <h4> 8 File Iteration 9 </h4> 10 <div> 11 File iteration is a complex, but powerful, vertical repetition construct. 12 It repeatedly includes a <i>file</i> for each number in a user-specified range. 13 </div> 14 <h4> 15 Tutorial 16 </h4> 17 <div> 18 This mechanism requires two pieces of information to operate: a range to 19 iterate over and a file to include on each iteration. It can optionally 20 take a third piece of information that represents flags used to discriminate 21 between different iterations of the same file. This information is 22 obtained by the mechanism through one or two <i>named external arguments</i>. 23 These arguments are specified as user-defined macros named <b>BOOST_PP_ITERATION_PARAMS_<i>x</i></b> 24 or the combination of <b>BOOST_PP_FILENAME_<i>x</i></b> and <b>BOOST_PP_ITERATION_LIMITS</b>. 25 </div> 26 <div> 27 <b>BOOST_PP_ITERATION_LIMITS</b> specifies the range of values to iterate 28 over. It <i>must</i> expand to a <i>tuple</i> containing two elements--a 29 lower and upper bound. Both the upper and lower bounds must be numeric 30 values in the range of <i>0</i> to <b>BOOST_PP_LIMIT_ITERATION</b>. For 31 example, if the user wishes a file to be included for numbers ranging from <i>0</i> 32 to <i>10</i>, <b>BOOST_PP_ITERATION_LIMITS</b> would be defined like this: 33 </div> 34 <div class="code"> 35 <pre> 36#define BOOST_PP_ITERATION_LIMITS (0, 10) 37</pre> 38 </div> 39 <div> 40 Note that there is whitespace after the name of the macro. The macro <i>does 41 not</i> take <i>two</i> arguments. In the case above, if there was 42 no whitespace, a preprocessing error would occur because <i>0</i> and <i>10</i> 43 are invalid identifiers. 44 </div> 45 <div> 46 Both the upper and lower bounds specified in the <b>BOOST_PP_ITERATION_LIMITS</b> 47 macro are <i>evaluated parameters</i>. This implies that they can include 48 simple arithmetic or logical expressions. For instance, the above 49 definition could easily have been written like this: 50 </div> 51 <div class="code"> 52 <pre> 53#define N() 5 54#define BOOST_PP_ITERATION_LIMITS (0, N() + 5) 55</pre> 56 </div> 57 <div> 58 Because of this, if the whitespace after the macro name is elided, it is 59 possible for the definition to be syntactically valid: 60 </div> 61 <div class="code"> 62 <pre> 63#define A 0 64#define B 10 65#define BOOST_PP_ITERATION_LIMITS(A, B) 66 // note: no whitespace ^ 67</pre> 68 </div> 69 <div> 70 If this happens, an error will occur inside the mechanism when it attempts to 71 use this macro. The error messages that result may be obscure, so always 72 remember to include the whitespace. A <i>correct</i> version of the above 73 looks like this: 74 </div> 75 <div class="code"> 76 <pre> 77#define A 0 78#define B 10 79#define BOOST_PP_ITERATION_LIMITS (A, B) 80 // note: has whitespace ^ 81</pre> 82 </div> 83 <div> 84 <b>BOOST_PP_FILENAME_<i>x</i></b> specifies the file to iterate over. The <i>x</i> 85 is a placeholder for the dimension of iteration. (For now, we'll assume 86 this is <i>1</i>--i.e. the first dimension, so we are actually dealing with <b>BOOST_PP_FILENAME_1</b>.) 87 This macro must expand to a valid filename--in quotes or in angle brackets 88 depending on how the file is accessed: 89 </div> 90 <div class="code"> 91 <pre> 92#define BOOST_PP_FILENAME_1 "file.h" 93// -or- 94#define BOOST_PP_FILENAME_1 <file.h> 95</pre> 96 </div> 97 <div> 98 All that we need now to perform a simple file iteration is to invoke the 99 mechanism: 100 </div> 101 <div class="code"> 102 <pre> 103??=include BOOST_PP_ITERATE() 104</pre> 105 </div> 106 <div> 107 (The <code>??=</code> token is a trigraph for <code>#</code>. I use the 108 trigraph to make it clear that I am <i>including</i> a file rather than 109 defining or expanding a macro, but it is not necessary. Even the digraph 110 version, <code>%:</code>, could be used. Some compilers do not readily 111 accept trigraphs and digraphs, so keep that in mind. Other than that, use 112 whichever one you prefer.) 113 </div> 114 <div> 115 So, if we wish to iterate "file.h" from <i>1</i> to <i>10</i>, we just need to 116 put the pieces together: 117 </div> 118 <div class="code"> 119 <pre> 120#define BOOST_PP_ITERATION_LIMITS (1, 10) 121#define BOOST_PP_FILENAME_1 "file.h" 122??=include BOOST_PP_ITERATE() 123</pre> 124 </div> 125 <div> 126 The above code has the effect of including "file.h" ten times in 127 succession. 128 </div> 129 <div> 130 Alternately, both the range and the file to iterate over can be expressed in 131 one macro, <b>BOOST_PP_ITERATION_PARAMS_<i>x</i></b>. Once again, the <i>x</i> 132 is a placeholder for the dimension of iteration--which we'll assume is <i>1</i>. 133 This macro must expand to an <i>array</i> that includes the lower bound, upper 134 bound, filename, and optional flags (in that order). 135 </div> 136 <div class="code"> 137 <pre> 138#define BOOST_PP_ITERATION_PARAMS_1 (3, (1, 10, "file.h")) 139??=include BOOST_PP_ITERATE() 140</pre> 141 </div> 142 <div> 143 This has the same effect as the previous version. Only one of these two 144 ways to specify the parameters can be used at a time. (The reason that 145 there are two different methods has to do with dimensional abstraction which 146 I'll get to later.) 147 </div> 148 <div> 149 There is nothing particularly useful about including a file ten times. 150 The difference is that the current macro state changes each time. For 151 example, the current "iteration value" is available with <b>BOOST_PP_ITERATION</b>(). 152 If "file.h" is defined like this... 153 </div> 154 <div class="code"> 155 <pre> 156// file.h 157template<> struct sample<BOOST_PP_ITERATION()> { }; 158</pre> 159 </div> 160 <div> 161 ...and it is iterated as follows... 162 </div> 163 <div class="code"> 164 <pre> 165template<int> struct sample; 166 167#define BOOST_PP_ITERATION_PARAMS_1 (3, (1, 5, "file.h")) 168??=include BOOST_PP_ITERATE() 169</pre> 170 </div> 171 <div> 172 ...the result is different each time: 173 </div> 174 <div> 175 <pre> 176template<> struct sample<1> { }; 177template<> struct sample<2> { }; 178template<> struct sample<3> { }; 179template<> struct sample<4> { }; 180template<> struct sample<5> { }; 181</pre> 182 </div> 183 <div> 184 There is no reason that a file can't iterate over itself. This has the 185 advantage of keeping the code together. The problem is that you have to 186 discriminate the "regular" section of the file from the iterated section of the 187 file. The library provides the <b>BOOST_PP_IS_ITERATING</b> macro to help 188 in this regard. This macro is defined as <i>1</i> if an iteration is in 189 progress. For example, to merge the contents of "file.h" into the file 190 that iterates it: 191 </div> 192 <div class="code"> 193 <pre> 194// sample.h 195#if !BOOST_PP_IS_ITERATING 196 197 #ifndef SAMPLE_H 198 #define SAMPLE_H 199 200 #include <boost/preprocessor/iteration/iterate.hpp> 201 202 template<int> struct sample; 203 204 #define BOOST_PP_ITERATION_PARAMS_1 (3, (1, 5, "sample.h")) 205 ??=include BOOST_PP_ITERATE() 206 207 #endif // SAMPLE_H 208 209#else 210 211 template<> struct sample<BOOST_PP_ITERATION()> { }; 212 213#endif 214</pre> 215 </div> 216 <div> 217 Using the same file like this raises another issue. What happens when a 218 file performs two separate file iterations over itself? This is the 219 purpose of the optional flags parameter. It is used to discriminate 220 between separate iterations. 221 </div> 222 <div class="code"> 223 <pre> 224// sample.h 225#if !BOOST_PP_IS_ITERATING 226 227 #ifndef SAMPLE_H 228 #define SAMPLE_H 229 230 #include <boost/preprocessor/iteration/iterate.hpp> 231 #include <boost/preprocessor/repetition/enum_params.hpp> 232 #include <boost/preprocessor/repetition/enum_shifted_params.hpp> 233 234 template<int> struct sample; 235 236 #define BOOST_PP_ITERATION_PARAMS_1 (4, (1, 5, "sample.h", 1)) 237 ??=include BOOST_PP_ITERATE() 238 239 template<class T, class U> struct typelist_t { 240 typedef T head; 241 typedef U tail; 242 }; 243 244 template<int> struct typelist; 245 struct null_t; 246 247 template<> struct typelist<1> { 248 template<class T0> struct args { 249 typedef typelist_t<T0, null_t> type; 250 }; 251 }; 252 253 #ifndef TYPELIST_MAX 254 #define TYPELIST_MAX 50 255 #endif 256 257 #define BOOST_PP_ITERATION_PARAMS_1 (4, (2, TYPELIST_MAX, "sample.h", 2)) 258 ??=include BOOST_PP_ITERATE() 259 260 #endif // SAMPLE_H 261 262#elif BOOST_PP_ITERATION_FLAGS() == 1 263 264 template<> struct sample<BOOST_PP_ITERATION()> { }; 265 266#elif BOOST_PP_ITERATION_FLAGS() == 2 267 268 #define N BOOST_PP_ITERATION() 269 270 template<> struct typelist<N> { 271 template<BOOST_PP_ENUM_PARAMS(N, class T)> struct args { 272 typedef typelist_t< 273 T0, 274 typename typelist<N - 1>::args<BOOST_PP_ENUM_SHIFTED_PARAMS(N, T)>::type 275 > type; 276 }; 277 }; 278 279 #undef N 280 281#endif 282</pre> 283 </div> 284 <div> 285 Notice the use of the "flags" parameter (which is accessed through <b>BOOST_PP_ITERATION_FLAGS</b>()). 286 It discriminates between our recurring <code>sample</code> iteration and a 287 typelist linearization iteration. 288 </div> 289 <div> 290 The second iteration illustrates the power of the file iteration 291 mechanism. It generates typelist linearizations of the form <code>typelist<3>::args<int, 292 double, char>::type</code>. 293 </div> 294 <div> 295 Actually, to continue the typelist example, with the help of another iteration 296 we can <i>fully</i> linearize typelist creation.... 297 </div> 298 <div class="code"> 299 <pre> 300// extract.h 301#if !BOOST_PP_IS_ITERATING 302 303 #ifndef EXTRACT_H 304 #define EXTRACT_H 305 306 #include <boost/preprocessor/iteration/iterate.hpp> 307 #include <boost/preprocessor/repetition/enum.hpp> 308 #include <boost/preprocessor/repetition/enum_params.hpp> 309 #include <boost/preprocessor/repetition/enum_trailing_params.hpp> 310 311 // certain types such as "void" can't be function argument types 312 313 template<class T> struct incomplete { 314 typedef T type; 315 }; 316 317 template<class T> struct strip_incomplete { 318 typedef T type; 319 }; 320 321 template<class T> struct strip_incomplete<incomplete<T> > { 322 typedef T type; 323 }; 324 325 template<template<int> class output, class func_t> struct extract; 326 327 #ifndef EXTRACT_MAX 328 #define EXTRACT_MAX 50 329 #endif 330 331 #define BOOST_PP_ITERATION_PARAMS_1 (3, (1, EXTRACT_MAX, "extract.h")) 332 ??=include BOOST_PP_ITERATE() 333 334 #endif // EXTRACT_H 335 336#else 337 338 #define N BOOST_PP_ITERATION() 339 #define STRIP(z, n, _) \ 340 typename strip_incomplete<T ## n>::type \ 341 /**/ 342 343 template<template<int> class output, class R BOOST_PP_ENUM_TRAILING_PARAMS(N, class T)> 344 struct extract<R (BOOST_PP_ENUM_PARAMS(N, T))> { 345 typedef typename output<N>::template args<BOOST_PP_ENUM(N, STRIP, nil)>::type type; 346 }; 347 348 #undef STRIP 349 #undef N 350 351#endif 352</pre> 353 </div> 354 <div> 355 Now we can define a helper macro to finish the job: 356 </div> 357 <div class="code"> 358 <pre> 359#define TYPELIST(args) extract<typelist, void args>::type 360 361typedef TYPELIST((int, double, incomplete<void>)) xyz; 362</pre> 363 </div> 364 <div> 365 There are two minor caveats with this result. First, certain types like <code>void</code> 366 can't be the type of an argument, so they have to be wrapped with <code>incomplete<T></code>. 367 Second, the necessary double parenthesis is annoying. If and when C++ 368 gets C99's variadic macros, <code>TYPELIST</code> can be redefined: 369 </div> 370 <div class="code"> 371 <pre> 372#define TYPELIST(...) extract<typelist, void (__VA_ARGS__)>::type 373 374typedef TYPELIST(int, double, short) xyz; 375</pre> 376 </div> 377 <div> 378 Note also that both the lower and upper bounds of an iteration are also 379 accessible inside an iteration with <b>BOOST_PP_ITERATION_START</b>() and <b>BOOST_PP_ITERATION_FINISH</b>(). 380 </div> 381 <div> 382 It is my hope that the explanation and examples presented here demonstrate the 383 power of file iteration. Even so, this is just the beginning. The 384 file iteration mechanism also defines a full suite of facilities to support 385 multidimensional iteration. 386 </div> 387 <h4> 388 Multiple Dimensions 389 </h4> 390 <div> 391 The file iteration mechanism supports up to <b>BOOST_PP_LIMIT_ITERATION_DIM</b> 392 dimensions. The first dimension (i.e. the outermost) we have already used 393 above. In order to use the second dimension (inside the first), we simply 394 have to replace the placeholder <i>x</i> with <i>2</i> instead of <i>1</i>. 395 </div> 396 <div class="code"> 397 <pre> 398#define BOOST_PP_ITERATION_PARAMS_2 /* ... */ 399 ^ 400</pre> 401 </div> 402 <div> 403 ...or... 404 </div> 405 <div class="code"> 406 <pre> 407#define BOOST_PP_FILENAME_2 /* ... */ 408 ^ 409</pre> 410 </div> 411 <div> 412 Each dimension must be used <i>in order</i> starting with <i>1</i>. 413 Therefore, the above can <i>only</i> be valid immediately inside the first 414 dimension. 415 </div> 416 <div> 417 At this point, further explanation is necessary regarding <b>BOOST_PP_ITERATION</b>, 418 <b>BOOST_PP_ITERATION_START</b>, and <b>BOOST_PP_ITERATION_FINISH</b>. <b>BOOST_PP_ITERATION</b>() 419 expands to the iteration value of the <i>current</i> dimension--regardless of 420 what dimension that is. Likewise, <b>BOOST_PP_ITERATION_START</b>() and <b>BOOST_PP_ITERATION_FINISH</b>() 421 expand to the lower and upper bounds of the <i>current</i> dimension. 422 Using the following pseudo-code as reference: 423 </div> 424 <div class="code"> 425 <pre> 426for (int i = start(1); i <= finish(1); ++i) { 427 // A 428 for (int j = start(2); j <= finish(2); ++j) { 429 // B 430 } 431 // C 432} 433</pre> 434 </div> 435 <div> 436 At point <i>A</i>, <b>BOOST_PP_ITERATION</b>() refers to <code>i</code>. <b>BOOST_PP_ITERATION_START</b>() 437 and <b>BOOST_PP_ITERATION_FINISH</b>() refer to <code>start(1)</code> and <code>finish(1)</code> 438 respectively. At point <i>B</i>, however, <b>BOOST_PP_ITERATION</b>() 439 refers to <code>j</code>--the <i>current</i> iteration value at point <i>B</i>. 440 The same is true for <b>BOOST_PP_ITERATION_START</b>() which refers to <code>start(2)</code>, 441 etc.. 442 </div> 443 <div> 444 If separate files are used for each dimension, then there are no major 445 problems, and using multiple dimensions is straightforward. However, if 446 more than one dimension is located in the same file, they need to be 447 distinguished from one another. The file iteration mechanism provides the 448 macro <b>BOOST_PP_ITERATION_DEPTH</b> for this purpose: 449 </div> 450 <div class="code"> 451 <pre> 452// file.h 453#if !BOOST_PP_IS_ITERATING 454 455 #ifndef FILE_H 456 #define FILE_H 457 458 #include <boost/preprocessor/iteration/iterate.hpp> 459 460 #define BOOST_PP_ITERATION_PARAMS_1 (3, (1, 2, "file.h")) 461 ??=include BOOST_PP_ITERATE() 462 463 #endif // FILE_H 464 465#elif BOOST_PP_ITERATION_DEPTH() == 1 466 467 // A 468 + BOOST_PP_ITERATION() 469 470 #define BOOST_PP_ITERATION_PARAMS_2 (3, (1, 2, "file.h")) 471 ??=include BOOST_PP_ITERATE() 472 473 // C 474 475#elif BOOST_PP_ITERATION_DEPTH() == 2 476 477 // B 478 - BOOST_PP_ITERATION() 479 480#endif 481</pre> 482 </div> 483 <div> 484 This will result to the following: 485 </div> 486 <div> 487 <pre> 488+ 1 489- 1 490- 2 491+ 2 492- 1 493- 2 494</pre> 495 </div> 496 <div> 497 Multiple dimensions raise another question. How does one access the state 498 of dimensions <i>other</i> than the current dimension? In other words, 499 how does one access <code>i</code> at point <i>A</i>? Because of the 500 preprocessor's lazy evaluation, this <i>doesn't</i> work.... 501 </div> 502 <div class="code"> 503 <pre> 504// ... 505 506#elif BOOST_PP_ITERATION_DEPTH() == 1 507 508 #define I BOOST_PP_ITERATION() 509 510 #define BOOST_PP_ITERATION_PARAMS_2 (3, (1, 2, "file.h")) 511 ??=include BOOST_PP_ITERATE() 512 513 #undef I 514 515#elif BOOST_PP_ITERATION_DEPTH() == 2 516 517 #define J BOOST_PP_ITERATION() 518 519 // use I and J 520 521 #undef I 522 523#endif 524</pre> 525 </div> 526 <div> 527 The problem here is that <code>I</code> refers to <b>BOOST_PP_ITERATION</b>(), 528 not to the <i>value</i> of <b>BOOST_PP_ITERATION</b>() at the point of <code>I</code>'s 529 definition. 530 </div> 531 <div> 532 The library provides macros to access these values in two ways--absolutely or 533 relatively. The first variety accesses a value of a specific iteration 534 frame (i.e. dimension). To access the iteration value of the first 535 dimension--from <i>any</i> dimension--<b>BOOST_PP_FRAME_ITERATION</b>(<i>1</i>) 536 is used. To access the iteration value of the second dimension, <b>BOOST_PP_FRAME_ITERATION</b>(<i>2</i>) 537 is used, and so on. 538 </div> 539 <div> 540 There are also frame versions to access the lower bound, the upper bound, and 541 the flags of a dimension: <b>BOOST_PP_FRAME_START</b>, <b>BOOST_PP_FRAME_FINISH</b>, 542 and <b>BOOST_PP_FRAME_FLAGS</b>. 543 </div> 544 <div> 545 So, to fix the last example, we modify the definition of <code>I</code>.... 546 </div> 547 <div class="code"> 548 <pre> 549// ... 550 551#elif BOOST_PP_ITERATION_DEPTH() == 1 552 553 #define I BOOST_PP_FRAME_ITERATION(1) 554 555// ... 556</pre> 557 </div> 558 <div> 559 The library also provides macros to access values in dimensions <i>relative</i> 560 to the current dimension (e.g. the <i>previous</i> dimension). These 561 macros take an argument that is interpreted as an offset from the current 562 frame. For example, <b>BOOST_PP_RELATIVE_ITERATION</b>(<i>1</i>) always 563 refers to the outer dimension immediately previous to the current 564 dimension. An argument of <i>0</i> is interpreted as an offset of <i>0</i> 565 which causes <b>BOOST_PP_RELATIVE_ITERATION</b>(<i>0</i>) to be equivalent to <b>BOOST_PP_ITERATION</b>(). 566 <b>BOOST_PP_RELATIVE_ITERATION</b>(<i>2</i>) refers to the iteration value of 567 the dimension immediately preceding the dimension that precedes the current 568 dimension. 569 </div> 570 <div> 571 The lower and upper bounds of a dimension can be accessed in this fashion as 572 well with <b>BOOST_PP_RELATIVE_START</b> and <b>BOOST_PP_RELATIVE_FINISH</b>. 573 The flags of a relative dimension can be accessed with <b>BOOST_PP_RELATIVE_FLAGS</b>. 574 </div> 575 <h4> 576 Relativity 577 </h4> 578 <div> 579 I mentioned earlier that there is a reason that there are two ways to 580 parametize the mechanism. The reason is dimensional abstraction. In 581 certain situations the dimension is unknown by the code that is being 582 iterated--possibly because the code is reused at multiple, different 583 dimensions. If that code needs to iterate again, it has to define the 584 right parameters (based on the dimension) for the mechanism to consume. 585 </div> 586 <div> 587 All of the macro state maintained by the mechanism can be referred to in an 588 indirect way relative to a dimension. This is the purpose of the <b>BOOST_PP_RELATIVE_</b> 589 accessors. 590 </div> 591 <div> 592 Likewise, the user-defined <i>named external arguments</i> can be defined this 593 way as well--<i>except</i> the name of the file to iterate. Because the 594 lower and upper boundaries are <i>evaluated</i> by the mechanism, the 595 implementation no longer needs the macro <b>BOOST_PP_ITERATION_LIMITS</b>, and 596 the identifier can be reused for each dimension of iteration. 597 </div> 598 <div> 599 Unfortunately, the filename is a different story. The library has no way 600 to evaluate the quoted (or angle-bracketed) text. Therefore, it has to 601 use a different macro for each dimension. That is the purpose of the <b>BOOST_PP_FILENAME_<i>x</i></b> 602 macros. They exist to isolate the only non-abstractable piece of data 603 required by the mechanism. 604 </div> 605 <div> 606 In order to define the filename in an abstract fashion, you need to do 607 something like this: 608 </div> 609 <div class="code"> 610 <pre> 611#define UNIQUE_TO_FILE "some_file.h" 612 613#if BOOST_PP_ITERATION_DEPTH() == 0 614 #define BOOST_PP_FILENAME_1 UNIQUE_TO_FILE 615#elif BOOST_PP_ITERATION_DEPTH() == 1 616 #define BOOST_PP_FILENAME_2 UNIQUE_TO_FILE 617#elif BOOST_PP_ITERATION_DEPTH() == 2 618 #define BOOST_PP_FILENAME_3 UNIQUE_TO_FILE 619 620// ... up to BOOST_PP_LIMIT_ITERATION_DIM 621 622#endif 623</pre> 624 </div> 625 <div> 626 The intent is to avoid having to do this for anything but the filename. 627 If this needs to be done more than once in a file (<b>BOOST_PP_FILENAME_<i>x</i></b> 628 is undefined by the mechanism after it is used.), consider using a separate 629 file to make the proper definition: 630 </div> 631 <div class="code"> 632 <pre> 633# // detail/define_file_h.h 634# ifndef FILE_H 635# error FILE_H is not defined 636# endif 637# 638# if BOOST_PP_ITERATION_DEPTH() == 0 639# define BOOST_PP_FILENAME_1 FILE_H 640# elif BOOST_PP_ITERATION_DEPTH() == 1 641# define BOOST_PP_FILENAME_2 FILE_H 642# elif BOOST_PP_ITERATION_DEPTH() == 2 643# define BOOST_PP_FILENAME_3 FILE_H 644# elif BOOST_PP_ITERATION_DEPTH() == 3 645# define BOOST_PP_FILENAME_4 FILE_H 646# elif BOOST_PP_ITERATION_DEPTH() == 4 647# define BOOST_PP_FILENAME_5 FILE_H 648# else 649# error unsupported iteration dimension 650# endif 651</pre> 652 </div> 653 <div> 654 And then use it like this.... 655 </div> 656 <div class="code"> 657 <pre> 658// file.h 659#if !BOOST_PP_IS_ITERATING 660 661 #ifndef FILE_H 662 #define FILE_H "file.h" 663 664 #define BOOST_PP_ITERATION_LIMITS (1, 10) 665 #include "detail/define_file_h.h" 666 667 ??=include BOOST_PP_ITERATE() 668 669#endif // FILE_H 670 671#else 672 // iterated portion 673#endif 674</pre> 675 </div> 676 <div> 677 With a little effort like this, it is possible to maintain the abstraction 678 without the code bloat that would otherwise be required. Unfortunately, 679 this is not a completely general solution as it would need to be done for each 680 unique filename, but it is better than nothing. 681 </div> 682 <h4> 683 Conclusion 684 </h4> 685 <div> 686 That about covers the facilities that are available from the mechanism. 687 Using these facilities, let's implement a <code>function_traits</code> template 688 to demonstrate a full-fledge use of the mechanism. 689 </div> 690 <h4> 691 Function Traits - An Involved Example 692 </h4> 693 <div> 694 Implementing a comprehensive <code>function_traits</code> template metafunction 695 requires the use of every major part of the file iteration mechanism. 696 </div> 697 <div> 698 (This example makes no attempt of work around compiler deficiencies and exists 699 only to illustrate the mechanism.) 700 </div> 701 <div> 702 The result should have the following features: 703 </div> 704 <ul> 705 <li> 706 return type</li> 707 <li> 708 number and types of parameters</li> 709 <li> 710 whether or not the type is a pointer-to-function, reference-to-function, 711 pointer-to-member-function, or a plain function type</li> 712 <li> 713 whether the type has an ellipsis</li> 714 <li> 715 if not a pointer-to-member-function, the equivalent pointer-to-function, 716 reference-to-function, and function type</li> 717 <li> 718 otherwise, the pointer-to-member type, the class type to which it refers, and 719 whether it is const and/or volatile qualified</li> 720 </ul> 721 <div> 722 There are a myriad of ways that this can be implemented. I'll give a 723 brief summary here of what is happening in the implementation below. 724 </div> 725 <div> 726 The implementation inherently has to deal with function arity. Therefore, 727 at minimum, we need to iterate over function arities and define partial 728 specializations of the primary template <code>function_traits</code>. The 729 situation is further complicated by variadic functions (i.e. functions with an 730 ellipsis). Therefore, for every arity, we need a variadic version as 731 well. 732 </div> 733 <div> 734 We also need to handle pointers-to-member-functions. This implies that we 735 have to handle not just arity and variadics, but also cv-qualifications. 736 </div> 737 <div> 738 For the sake of clarity, the implementation below handles function types and 739 pointers-to-member-functions separately. They could be merged, but the 740 result would be significantly messier. 741 </div> 742 <div> 743 To handle function types, the implementation below iterates over function 744 arities. For each arity, it iterates over each parameter to provide 745 access to each individually. It then re-includes itself to define a 746 variadic specialization of the same arity. It performs the rough 747 equivalent of the following pseudo-code: 748 </div> 749 <div class="code"> 750 <pre> 751void make_spec(int i, bool variadic) { 752 :open function_traits<i, variadic> 753 for (int j = 0; j < i; ++j) { 754 :parameter<j> 755 } 756 :close 757 if (!variadic) { 758 make_spec(i, true); 759 } 760 return; 761} 762 763void function_types(int max_arity) { 764 for (int i = 0; i <= max_arity; ++i) { 765 make_spec(i, false); 766 } 767 return; 768} 769</pre> 770 </div> 771 <div> 772 The implementation of pointers-to-member-functions is a bit different. 773 First, it iterates over cv-qualifiers. For each cv-qualifier, it iterates 774 over function arities. For each function arity, it iterates again over 775 each parameter. It then re-includes itself to define a variadic 776 specialization of the same arity.... 777 </div> 778 <div class="code"> 779 <pre> 780void make_spec(int j, const char* cv, bool variadic) { 781 :open function_traits<j, cv, variadic> 782 for (int k = 0; k < j; ++k) { 783 parameter<k> 784 } 785 :close 786 if (!variadic) { 787 make_spec(j, cv, true); 788 } 789 return; 790} 791 792void gen_arities(const char* cv, int max_arity) { 793 for (int j = 0; j <= max_arity; ++j) { 794 make_spec(j, cv, false); 795 } 796 return; 797} 798 799void pointers_to_members(int max_arity) { 800 static const char* cv_qualifiers[] = { "", "const", "volatile", "const volatile" }; 801 for (int i = 0; i < 4; ++i) { 802 gen_arities(cv_qualifiers[i], max_arity); 803 } 804 return; 805} 806</pre> 807 </div> 808 <div> 809 Here is the complete implementation. This example represents the power of 810 the file iteration mechanism as well as the library in general, so follow it 811 carefully if you wish to fully understand what the mechanism does.... 812 </div> 813 <div class="code"> 814 <pre> 815// function_traits.hpp 816 817#if !BOOST_PP_IS_ITERATING 818 819#ifndef FUNCTION_TRAITS_HPP 820#define FUNCTION_TRAITS_HPP 821 822#include <boost/preprocessor/cat.hpp> 823#include <boost/preprocessor/facilities/apply.hpp> 824#include <boost/preprocessor/iteration/iterate.hpp> 825#include <boost/preprocessor/iteration/self.hpp> 826#include <boost/preprocessor/repetition/enum_params.hpp> 827#include <boost/preprocessor/repetition/enum_trailing_params.hpp> 828#include <boost/preprocessor/tuple/elem.hpp> 829 830// enable user-expansion 831#ifndef FUNCTION_TRAITS_MAX_ARITY 832 #define FUNCTION_TRAITS_MAX_ARITY 15 833#endif 834 835namespace detail { 836 837// avoid replication of "default" values 838struct function_traits_base { 839 static const bool is_plain = false; 840 static const bool is_pointer = false; 841 static const bool is_reference = false; 842 static const bool is_member = false; 843}; 844 845} // detail 846 847// no definition 848template<class> struct function_traits; 849 850// extract ellipsis state 851#define ELLIPSIS(n) \ 852 BOOST_PP_APPLY( \ 853 BOOST_PP_TUPLE_ELEM(2, n, ELLIPSIS_I) \ 854 ) \ 855 /**/ 856 857// iterate over function arities for function types 858#define BOOST_PP_ITERATION_PARAMS_1 \ 859 (4, (0, FUNCTION_TRAITS_MAX_ARITY, "function_traits.hpp", 0)) \ 860 /**/ 861??=include BOOST_PP_ITERATE() 862 863// obtain a cv-qualifier by index 864#define QUALIFIER(n) \ 865 BOOST_PP_APPLY( \ 866 BOOST_PP_TUPLE_ELEM( \ 867 4, n, \ 868 (BOOST_PP_NIL, (const), (volatile), (const volatile)) \ 869 ) \ 870 ) \ 871 /**/ 872 873// iterate over cv-qualifiers for pointers-to-members 874#define BOOST_PP_ITERATION_PARAMS_1 \ 875 (4, (0, 3, "function_traits.hpp", 1)) \ 876 /**/ 877??=include BOOST_PP_ITERATE() 878 879// remove temporary macros 880#undef QUALIFIER 881#undef ELLIPSIS 882 883// overriding jumper for pointers-to-functions 884template<class T> struct function_traits<T*> : function_traits<T> { 885 static const bool is_plain = false; 886 static const bool is_pointer = true; 887}; 888 889// overriding jumper for references-to-functions 890template<class T> struct function_traits<T&> : function_traits<T> { 891 static const bool is_plain = false; 892 static const bool is_reference = true; 893}; 894 895// eof 896#endif // FUNCTION_TRAITS_HPP 897 898// specializations for function types 899#elif BOOST_PP_ITERATION_DEPTH() == 1 \ 900 && BOOST_PP_ITERATION_FLAGS() == 0 \ 901 /**/ 902 903 // define ellipsis state 904 #if BOOST_PP_IS_SELFISH 905 #define ELLIPSIS_I ((true), (...)) 906 #else 907 #define ELLIPSIS_I ((false), BOOST_PP_NIL) 908 #endif 909 910 #define N BOOST_PP_ITERATION() 911 912 template<class R BOOST_PP_ENUM_TRAILING_PARAMS(N, class T)> 913 struct function_traits<R (BOOST_PP_ENUM_PARAMS(N, T) ELLIPSIS(1))> 914 : detail::function_traits_base { 915 static const bool is_plain = true; 916 typedef R function_type(BOOST_PP_ENUM_PARAMS(N, T) ELLIPSIS(1)); 917 typedef function_type* pointer_type; 918 typedef function_type& reference_type; 919 static const bool has_ellipsis = ELLIPSIS(0); 920 typedef R return_type; 921 static const int parameter_count = N; 922 template<int, class D = int> struct parameter; 923 #if N 924 // iterate over parameters 925 #define BOOST_PP_ITERATION_PARAMS_2 \ 926 (3, (0, N - 1, "function_traits.hpp")) \ 927 /**/ 928 ??=include BOOST_PP_ITERATE() 929 #endif 930 }; 931 932 #undef N 933 #undef ELLIPSIS_I 934 935 // re-include this section for an ellipsis variant 936 #if !BOOST_PP_IS_SELFISH 937 #define BOOST_PP_INDIRECT_SELF "function_traits.hpp" 938 ??=include BOOST_PP_INCLUDE_SELF() 939 #endif 940 941// iteration over cv-qualifiers 942#elif BOOST_PP_ITERATION_DEPTH() == 1 \ 943 && BOOST_PP_ITERATION_FLAGS() == 1 \ 944 /**/ 945 946 #define BOOST_PP_ITERATION_PARAMS_2 \ 947 (3, (0, FUNCTION_TRAITS_MAX_ARITY, "function_traits.hpp")) \ 948 /**/ 949 ??=include BOOST_PP_ITERATE() 950 951// generate specializations for pointers-to-members 952#elif BOOST_PP_ITERATION_DEPTH() == 2 \ 953 && BOOST_PP_FRAME_FLAGS(1) == 1 \ 954 955 // define ellipsis state 956 #if BOOST_PP_IS_SELFISH 957 #define ELLIPSIS_I ((true), (...)) 958 #else 959 #define ELLIPSIS_I ((false), BOOST_PP_NIL) 960 #endif 961 962 #define N BOOST_PP_ITERATION() 963 #define Q QUALIFIER(BOOST_PP_FRAME_ITERATION(1)) 964 965 template<class R, class O BOOST_PP_ENUM_TRAILING_PARAMS(N, class T)> 966 struct function_traits<R (O::*)(BOOST_PP_ENUM_PARAMS(N, T) ELLIPSIS(1)) Q> 967 : detail::function_traits_base { 968 static const bool is_member = true; 969 typedef R (O::* pointer_to_member_type)(BOOST_PP_ENUM_PARAMS(N, T) ELLIPSIS(1)) Q; 970 typedef O class_type; 971 typedef Q O qualified_class_type; 972 static const bool has_ellipsis = ELLIPSIS(0); 973 static const bool is_const = 974 BOOST_PP_FRAME_ITERATION(1) == 1 || BOOST_PP_FRAME_ITERATION(1) == 3; 975 static const bool is_volatile = 976 BOOST_PP_FRAME_ITERATION(1) == 2 || BOOST_PP_FRAME_ITERATION(1) == 3; 977 typedef R return_type; 978 static const int parameter_count = N; 979 template<int, class D = int> struct parameter; 980 #if N 981 // iterate over parameters 982 #define BOOST_PP_ITERATION_PARAMS_3 \ 983 (3, (0, N - 1, "function_traits.hpp")) \ 984 /**/ 985 ??=include BOOST_PP_ITERATE() 986 #endif 987 }; 988 989 #undef Q 990 #undef N 991 #undef ELLIPSIS_I 992 993 // re-include this section for an ellipsis variant 994 #if !BOOST_PP_IS_SELFISH 995 #define BOOST_PP_INDIRECT_SELF "function_traits.hpp" 996 ??=include BOOST_PP_INCLUDE_SELF() 997 #endif 998 999// parameter specializations 1000#else 1001 1002 #define X BOOST_PP_ITERATION() 1003 1004 template<class D> struct parameter<X, D> { 1005 typedef BOOST_PP_CAT(T, X) type; 1006 }; 1007 1008 #undef X 1009 1010#endif 1011</pre> 1012 </div> 1013 <div> 1014 One problem that still exists is the lack of support for <code>throw</code> specifications. 1015 There is no way that we can completely handle it anyway because we cannot 1016 partially specialize on <code>throw</code> specifications. However, we 1017 could accurately report the "actual" function type, etc., including the <code>throw</code> 1018 specification (which the above implementation doesn't do, as it reconstructs 1019 those types). If you like, you can figure out how to do that on your own 1020 as an exercise. 1021 </div> 1022 <h4> 1023 See Also 1024 </h4> 1025 <ul> 1026 <li> 1027 <a href="../ref/iterate.html">BOOST_PP_ITERATE</a></li> 1028 </ul> 1029 <div class="sig"> 1030 - Paul Mensonides 1031 </div> 1032 <hr size="1"> 1033 <div style="margin-left: 0px;"> 1034 <i>� Copyright <a href="http://www.housemarque.com" target="_top">Housemarque Oy</a> 2002</i> 1035 </br><i>� Copyright Paul Mensonides 2002</i> 1036 </div> 1037 <div style="margin-left: 0px;"> 1038 <p><small>Distributed under the Boost Software License, Version 1.0. (See 1039 accompanying file <a href="../../../../LICENSE_1_0.txt">LICENSE_1_0.txt</a> or 1040 copy at <a href= 1041 "http://www.boost.org/LICENSE_1_0.txt">www.boost.org/LICENSE_1_0.txt</a>)</small></p> 1042 </div> 1043 </body> 1044</html> 1045