Brian Silverman | f27e085 | 2018-08-04 23:56:45 -0700 | [diff] [blame^] | 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 |
| 157 | template<> 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> |
| 165 | template<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> |
| 176 | template<> struct sample<1> { }; |
| 177 | template<> struct sample<2> { }; |
| 178 | template<> struct sample<3> { }; |
| 179 | template<> struct sample<4> { }; |
| 180 | template<> 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 | |
| 361 | typedef 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 | |
| 374 | typedef 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> |
| 426 | for (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> |
| 751 | void 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 | |
| 763 | void 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> |
| 780 | void 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 | |
| 792 | void 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 | |
| 799 | void 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 | |
| 835 | namespace detail { |
| 836 | |
| 837 | // avoid replication of "default" values |
| 838 | struct 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 |
| 848 | template<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 |
| 884 | template<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 |
| 890 | template<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> |