| <html> |
| <head> |
| <title>file_iteration.html</title> |
| <link rel="stylesheet" type="text/css" href="../styles.css"> |
| </head> |
| <body> |
| <h4> |
| File Iteration |
| </h4> |
| <div> |
| File iteration is a complex, but powerful, vertical repetition construct. |
| It repeatedly includes a <i>file</i> for each number in a user-specified range. |
| </div> |
| <h4> |
| Tutorial |
| </h4> |
| <div> |
| This mechanism requires two pieces of information to operate: a range to |
| iterate over and a file to include on each iteration. It can optionally |
| take a third piece of information that represents flags used to discriminate |
| between different iterations of the same file. This information is |
| obtained by the mechanism through one or two <i>named external arguments</i>. |
| These arguments are specified as user-defined macros named <b>BOOST_PP_ITERATION_PARAMS_<i>x</i></b> |
| or the combination of <b>BOOST_PP_FILENAME_<i>x</i></b> and <b>BOOST_PP_ITERATION_LIMITS</b>. |
| </div> |
| <div> |
| <b>BOOST_PP_ITERATION_LIMITS</b> specifies the range of values to iterate |
| over. It <i>must</i> expand to a <i>tuple</i> containing two elements--a |
| lower and upper bound. Both the upper and lower bounds must be numeric |
| values in the range of <i>0</i> to <b>BOOST_PP_LIMIT_ITERATION</b>. For |
| example, if the user wishes a file to be included for numbers ranging from <i>0</i> |
| to <i>10</i>, <b>BOOST_PP_ITERATION_LIMITS</b> would be defined like this: |
| </div> |
| <div class="code"> |
| <pre> |
| #define BOOST_PP_ITERATION_LIMITS (0, 10) |
| </pre> |
| </div> |
| <div> |
| Note that there is whitespace after the name of the macro. The macro <i>does |
| not</i> take <i>two</i> arguments. In the case above, if there was |
| no whitespace, a preprocessing error would occur because <i>0</i> and <i>10</i> |
| are invalid identifiers. |
| </div> |
| <div> |
| Both the upper and lower bounds specified in the <b>BOOST_PP_ITERATION_LIMITS</b> |
| macro are <i>evaluated parameters</i>. This implies that they can include |
| simple arithmetic or logical expressions. For instance, the above |
| definition could easily have been written like this: |
| </div> |
| <div class="code"> |
| <pre> |
| #define N() 5 |
| #define BOOST_PP_ITERATION_LIMITS (0, N() + 5) |
| </pre> |
| </div> |
| <div> |
| Because of this, if the whitespace after the macro name is elided, it is |
| possible for the definition to be syntactically valid: |
| </div> |
| <div class="code"> |
| <pre> |
| #define A 0 |
| #define B 10 |
| #define BOOST_PP_ITERATION_LIMITS(A, B) |
| // note: no whitespace ^ |
| </pre> |
| </div> |
| <div> |
| If this happens, an error will occur inside the mechanism when it attempts to |
| use this macro. The error messages that result may be obscure, so always |
| remember to include the whitespace. A <i>correct</i> version of the above |
| looks like this: |
| </div> |
| <div class="code"> |
| <pre> |
| #define A 0 |
| #define B 10 |
| #define BOOST_PP_ITERATION_LIMITS (A, B) |
| // note: has whitespace ^ |
| </pre> |
| </div> |
| <div> |
| <b>BOOST_PP_FILENAME_<i>x</i></b> specifies the file to iterate over. The <i>x</i> |
| is a placeholder for the dimension of iteration. (For now, we'll assume |
| this is <i>1</i>--i.e. the first dimension, so we are actually dealing with <b>BOOST_PP_FILENAME_1</b>.) |
| This macro must expand to a valid filename--in quotes or in angle brackets |
| depending on how the file is accessed: |
| </div> |
| <div class="code"> |
| <pre> |
| #define BOOST_PP_FILENAME_1 "file.h" |
| // -or- |
| #define BOOST_PP_FILENAME_1 <file.h> |
| </pre> |
| </div> |
| <div> |
| All that we need now to perform a simple file iteration is to invoke the |
| mechanism: |
| </div> |
| <div class="code"> |
| <pre> |
| ??=include BOOST_PP_ITERATE() |
| </pre> |
| </div> |
| <div> |
| (The <code>??=</code> token is a trigraph for <code>#</code>. I use the |
| trigraph to make it clear that I am <i>including</i> a file rather than |
| defining or expanding a macro, but it is not necessary. Even the digraph |
| version, <code>%:</code>, could be used. Some compilers do not readily |
| accept trigraphs and digraphs, so keep that in mind. Other than that, use |
| whichever one you prefer.) |
| </div> |
| <div> |
| So, if we wish to iterate "file.h" from <i>1</i> to <i>10</i>, we just need to |
| put the pieces together: |
| </div> |
| <div class="code"> |
| <pre> |
| #define BOOST_PP_ITERATION_LIMITS (1, 10) |
| #define BOOST_PP_FILENAME_1 "file.h" |
| ??=include BOOST_PP_ITERATE() |
| </pre> |
| </div> |
| <div> |
| The above code has the effect of including "file.h" ten times in |
| succession. |
| </div> |
| <div> |
| Alternately, both the range and the file to iterate over can be expressed in |
| one macro, <b>BOOST_PP_ITERATION_PARAMS_<i>x</i></b>. Once again, the <i>x</i> |
| is a placeholder for the dimension of iteration--which we'll assume is <i>1</i>. |
| This macro must expand to an <i>array</i> that includes the lower bound, upper |
| bound, filename, and optional flags (in that order). |
| </div> |
| <div class="code"> |
| <pre> |
| #define BOOST_PP_ITERATION_PARAMS_1 (3, (1, 10, "file.h")) |
| ??=include BOOST_PP_ITERATE() |
| </pre> |
| </div> |
| <div> |
| This has the same effect as the previous version. Only one of these two |
| ways to specify the parameters can be used at a time. (The reason that |
| there are two different methods has to do with dimensional abstraction which |
| I'll get to later.) |
| </div> |
| <div> |
| There is nothing particularly useful about including a file ten times. |
| The difference is that the current macro state changes each time. For |
| example, the current "iteration value" is available with <b>BOOST_PP_ITERATION</b>(). |
| If "file.h" is defined like this... |
| </div> |
| <div class="code"> |
| <pre> |
| // file.h |
| template<> struct sample<BOOST_PP_ITERATION()> { }; |
| </pre> |
| </div> |
| <div> |
| ...and it is iterated as follows... |
| </div> |
| <div class="code"> |
| <pre> |
| template<int> struct sample; |
| |
| #define BOOST_PP_ITERATION_PARAMS_1 (3, (1, 5, "file.h")) |
| ??=include BOOST_PP_ITERATE() |
| </pre> |
| </div> |
| <div> |
| ...the result is different each time: |
| </div> |
| <div> |
| <pre> |
| template<> struct sample<1> { }; |
| template<> struct sample<2> { }; |
| template<> struct sample<3> { }; |
| template<> struct sample<4> { }; |
| template<> struct sample<5> { }; |
| </pre> |
| </div> |
| <div> |
| There is no reason that a file can't iterate over itself. This has the |
| advantage of keeping the code together. The problem is that you have to |
| discriminate the "regular" section of the file from the iterated section of the |
| file. The library provides the <b>BOOST_PP_IS_ITERATING</b> macro to help |
| in this regard. This macro is defined as <i>1</i> if an iteration is in |
| progress. For example, to merge the contents of "file.h" into the file |
| that iterates it: |
| </div> |
| <div class="code"> |
| <pre> |
| // sample.h |
| #if !BOOST_PP_IS_ITERATING |
| |
| #ifndef SAMPLE_H |
| #define SAMPLE_H |
| |
| #include <boost/preprocessor/iteration/iterate.hpp> |
| |
| template<int> struct sample; |
| |
| #define BOOST_PP_ITERATION_PARAMS_1 (3, (1, 5, "sample.h")) |
| ??=include BOOST_PP_ITERATE() |
| |
| #endif // SAMPLE_H |
| |
| #else |
| |
| template<> struct sample<BOOST_PP_ITERATION()> { }; |
| |
| #endif |
| </pre> |
| </div> |
| <div> |
| Using the same file like this raises another issue. What happens when a |
| file performs two separate file iterations over itself? This is the |
| purpose of the optional flags parameter. It is used to discriminate |
| between separate iterations. |
| </div> |
| <div class="code"> |
| <pre> |
| // sample.h |
| #if !BOOST_PP_IS_ITERATING |
| |
| #ifndef SAMPLE_H |
| #define SAMPLE_H |
| |
| #include <boost/preprocessor/iteration/iterate.hpp> |
| #include <boost/preprocessor/repetition/enum_params.hpp> |
| #include <boost/preprocessor/repetition/enum_shifted_params.hpp> |
| |
| template<int> struct sample; |
| |
| #define BOOST_PP_ITERATION_PARAMS_1 (4, (1, 5, "sample.h", 1)) |
| ??=include BOOST_PP_ITERATE() |
| |
| template<class T, class U> struct typelist_t { |
| typedef T head; |
| typedef U tail; |
| }; |
| |
| template<int> struct typelist; |
| struct null_t; |
| |
| template<> struct typelist<1> { |
| template<class T0> struct args { |
| typedef typelist_t<T0, null_t> type; |
| }; |
| }; |
| |
| #ifndef TYPELIST_MAX |
| #define TYPELIST_MAX 50 |
| #endif |
| |
| #define BOOST_PP_ITERATION_PARAMS_1 (4, (2, TYPELIST_MAX, "sample.h", 2)) |
| ??=include BOOST_PP_ITERATE() |
| |
| #endif // SAMPLE_H |
| |
| #elif BOOST_PP_ITERATION_FLAGS() == 1 |
| |
| template<> struct sample<BOOST_PP_ITERATION()> { }; |
| |
| #elif BOOST_PP_ITERATION_FLAGS() == 2 |
| |
| #define N BOOST_PP_ITERATION() |
| |
| template<> struct typelist<N> { |
| template<BOOST_PP_ENUM_PARAMS(N, class T)> struct args { |
| typedef typelist_t< |
| T0, |
| typename typelist<N - 1>::args<BOOST_PP_ENUM_SHIFTED_PARAMS(N, T)>::type |
| > type; |
| }; |
| }; |
| |
| #undef N |
| |
| #endif |
| </pre> |
| </div> |
| <div> |
| Notice the use of the "flags" parameter (which is accessed through <b>BOOST_PP_ITERATION_FLAGS</b>()). |
| It discriminates between our recurring <code>sample</code> iteration and a |
| typelist linearization iteration. |
| </div> |
| <div> |
| The second iteration illustrates the power of the file iteration |
| mechanism. It generates typelist linearizations of the form <code>typelist<3>::args<int, |
| double, char>::type</code>. |
| </div> |
| <div> |
| Actually, to continue the typelist example, with the help of another iteration |
| we can <i>fully</i> linearize typelist creation.... |
| </div> |
| <div class="code"> |
| <pre> |
| // extract.h |
| #if !BOOST_PP_IS_ITERATING |
| |
| #ifndef EXTRACT_H |
| #define EXTRACT_H |
| |
| #include <boost/preprocessor/iteration/iterate.hpp> |
| #include <boost/preprocessor/repetition/enum.hpp> |
| #include <boost/preprocessor/repetition/enum_params.hpp> |
| #include <boost/preprocessor/repetition/enum_trailing_params.hpp> |
| |
| // certain types such as "void" can't be function argument types |
| |
| template<class T> struct incomplete { |
| typedef T type; |
| }; |
| |
| template<class T> struct strip_incomplete { |
| typedef T type; |
| }; |
| |
| template<class T> struct strip_incomplete<incomplete<T> > { |
| typedef T type; |
| }; |
| |
| template<template<int> class output, class func_t> struct extract; |
| |
| #ifndef EXTRACT_MAX |
| #define EXTRACT_MAX 50 |
| #endif |
| |
| #define BOOST_PP_ITERATION_PARAMS_1 (3, (1, EXTRACT_MAX, "extract.h")) |
| ??=include BOOST_PP_ITERATE() |
| |
| #endif // EXTRACT_H |
| |
| #else |
| |
| #define N BOOST_PP_ITERATION() |
| #define STRIP(z, n, _) \ |
| typename strip_incomplete<T ## n>::type \ |
| /**/ |
| |
| template<template<int> class output, class R BOOST_PP_ENUM_TRAILING_PARAMS(N, class T)> |
| struct extract<R (BOOST_PP_ENUM_PARAMS(N, T))> { |
| typedef typename output<N>::template args<BOOST_PP_ENUM(N, STRIP, nil)>::type type; |
| }; |
| |
| #undef STRIP |
| #undef N |
| |
| #endif |
| </pre> |
| </div> |
| <div> |
| Now we can define a helper macro to finish the job: |
| </div> |
| <div class="code"> |
| <pre> |
| #define TYPELIST(args) extract<typelist, void args>::type |
| |
| typedef TYPELIST((int, double, incomplete<void>)) xyz; |
| </pre> |
| </div> |
| <div> |
| There are two minor caveats with this result. First, certain types like <code>void</code> |
| can't be the type of an argument, so they have to be wrapped with <code>incomplete<T></code>. |
| Second, the necessary double parenthesis is annoying. If and when C++ |
| gets C99's variadic macros, <code>TYPELIST</code> can be redefined: |
| </div> |
| <div class="code"> |
| <pre> |
| #define TYPELIST(...) extract<typelist, void (__VA_ARGS__)>::type |
| |
| typedef TYPELIST(int, double, short) xyz; |
| </pre> |
| </div> |
| <div> |
| Note also that both the lower and upper bounds of an iteration are also |
| accessible inside an iteration with <b>BOOST_PP_ITERATION_START</b>() and <b>BOOST_PP_ITERATION_FINISH</b>(). |
| </div> |
| <div> |
| It is my hope that the explanation and examples presented here demonstrate the |
| power of file iteration. Even so, this is just the beginning. The |
| file iteration mechanism also defines a full suite of facilities to support |
| multidimensional iteration. |
| </div> |
| <h4> |
| Multiple Dimensions |
| </h4> |
| <div> |
| The file iteration mechanism supports up to <b>BOOST_PP_LIMIT_ITERATION_DIM</b> |
| dimensions. The first dimension (i.e. the outermost) we have already used |
| above. In order to use the second dimension (inside the first), we simply |
| have to replace the placeholder <i>x</i> with <i>2</i> instead of <i>1</i>. |
| </div> |
| <div class="code"> |
| <pre> |
| #define BOOST_PP_ITERATION_PARAMS_2 /* ... */ |
| ^ |
| </pre> |
| </div> |
| <div> |
| ...or... |
| </div> |
| <div class="code"> |
| <pre> |
| #define BOOST_PP_FILENAME_2 /* ... */ |
| ^ |
| </pre> |
| </div> |
| <div> |
| Each dimension must be used <i>in order</i> starting with <i>1</i>. |
| Therefore, the above can <i>only</i> be valid immediately inside the first |
| dimension. |
| </div> |
| <div> |
| At this point, further explanation is necessary regarding <b>BOOST_PP_ITERATION</b>, |
| <b>BOOST_PP_ITERATION_START</b>, and <b>BOOST_PP_ITERATION_FINISH</b>. <b>BOOST_PP_ITERATION</b>() |
| expands to the iteration value of the <i>current</i> dimension--regardless of |
| what dimension that is. Likewise, <b>BOOST_PP_ITERATION_START</b>() and <b>BOOST_PP_ITERATION_FINISH</b>() |
| expand to the lower and upper bounds of the <i>current</i> dimension. |
| Using the following pseudo-code as reference: |
| </div> |
| <div class="code"> |
| <pre> |
| for (int i = start(1); i <= finish(1); ++i) { |
| // A |
| for (int j = start(2); j <= finish(2); ++j) { |
| // B |
| } |
| // C |
| } |
| </pre> |
| </div> |
| <div> |
| At point <i>A</i>, <b>BOOST_PP_ITERATION</b>() refers to <code>i</code>. <b>BOOST_PP_ITERATION_START</b>() |
| and <b>BOOST_PP_ITERATION_FINISH</b>() refer to <code>start(1)</code> and <code>finish(1)</code> |
| respectively. At point <i>B</i>, however, <b>BOOST_PP_ITERATION</b>() |
| refers to <code>j</code>--the <i>current</i> iteration value at point <i>B</i>. |
| The same is true for <b>BOOST_PP_ITERATION_START</b>() which refers to <code>start(2)</code>, |
| etc.. |
| </div> |
| <div> |
| If separate files are used for each dimension, then there are no major |
| problems, and using multiple dimensions is straightforward. However, if |
| more than one dimension is located in the same file, they need to be |
| distinguished from one another. The file iteration mechanism provides the |
| macro <b>BOOST_PP_ITERATION_DEPTH</b> for this purpose: |
| </div> |
| <div class="code"> |
| <pre> |
| // file.h |
| #if !BOOST_PP_IS_ITERATING |
| |
| #ifndef FILE_H |
| #define FILE_H |
| |
| #include <boost/preprocessor/iteration/iterate.hpp> |
| |
| #define BOOST_PP_ITERATION_PARAMS_1 (3, (1, 2, "file.h")) |
| ??=include BOOST_PP_ITERATE() |
| |
| #endif // FILE_H |
| |
| #elif BOOST_PP_ITERATION_DEPTH() == 1 |
| |
| // A |
| + BOOST_PP_ITERATION() |
| |
| #define BOOST_PP_ITERATION_PARAMS_2 (3, (1, 2, "file.h")) |
| ??=include BOOST_PP_ITERATE() |
| |
| // C |
| |
| #elif BOOST_PP_ITERATION_DEPTH() == 2 |
| |
| // B |
| - BOOST_PP_ITERATION() |
| |
| #endif |
| </pre> |
| </div> |
| <div> |
| This will result to the following: |
| </div> |
| <div> |
| <pre> |
| + 1 |
| - 1 |
| - 2 |
| + 2 |
| - 1 |
| - 2 |
| </pre> |
| </div> |
| <div> |
| Multiple dimensions raise another question. How does one access the state |
| of dimensions <i>other</i> than the current dimension? In other words, |
| how does one access <code>i</code> at point <i>A</i>? Because of the |
| preprocessor's lazy evaluation, this <i>doesn't</i> work.... |
| </div> |
| <div class="code"> |
| <pre> |
| // ... |
| |
| #elif BOOST_PP_ITERATION_DEPTH() == 1 |
| |
| #define I BOOST_PP_ITERATION() |
| |
| #define BOOST_PP_ITERATION_PARAMS_2 (3, (1, 2, "file.h")) |
| ??=include BOOST_PP_ITERATE() |
| |
| #undef I |
| |
| #elif BOOST_PP_ITERATION_DEPTH() == 2 |
| |
| #define J BOOST_PP_ITERATION() |
| |
| // use I and J |
| |
| #undef I |
| |
| #endif |
| </pre> |
| </div> |
| <div> |
| The problem here is that <code>I</code> refers to <b>BOOST_PP_ITERATION</b>(), |
| not to the <i>value</i> of <b>BOOST_PP_ITERATION</b>() at the point of <code>I</code>'s |
| definition. |
| </div> |
| <div> |
| The library provides macros to access these values in two ways--absolutely or |
| relatively. The first variety accesses a value of a specific iteration |
| frame (i.e. dimension). To access the iteration value of the first |
| dimension--from <i>any</i> dimension--<b>BOOST_PP_FRAME_ITERATION</b>(<i>1</i>) |
| is used. To access the iteration value of the second dimension, <b>BOOST_PP_FRAME_ITERATION</b>(<i>2</i>) |
| is used, and so on. |
| </div> |
| <div> |
| There are also frame versions to access the lower bound, the upper bound, and |
| the flags of a dimension: <b>BOOST_PP_FRAME_START</b>, <b>BOOST_PP_FRAME_FINISH</b>, |
| and <b>BOOST_PP_FRAME_FLAGS</b>. |
| </div> |
| <div> |
| So, to fix the last example, we modify the definition of <code>I</code>.... |
| </div> |
| <div class="code"> |
| <pre> |
| // ... |
| |
| #elif BOOST_PP_ITERATION_DEPTH() == 1 |
| |
| #define I BOOST_PP_FRAME_ITERATION(1) |
| |
| // ... |
| </pre> |
| </div> |
| <div> |
| The library also provides macros to access values in dimensions <i>relative</i> |
| to the current dimension (e.g. the <i>previous</i> dimension). These |
| macros take an argument that is interpreted as an offset from the current |
| frame. For example, <b>BOOST_PP_RELATIVE_ITERATION</b>(<i>1</i>) always |
| refers to the outer dimension immediately previous to the current |
| dimension. An argument of <i>0</i> is interpreted as an offset of <i>0</i> |
| which causes <b>BOOST_PP_RELATIVE_ITERATION</b>(<i>0</i>) to be equivalent to <b>BOOST_PP_ITERATION</b>(). |
| <b>BOOST_PP_RELATIVE_ITERATION</b>(<i>2</i>) refers to the iteration value of |
| the dimension immediately preceding the dimension that precedes the current |
| dimension. |
| </div> |
| <div> |
| The lower and upper bounds of a dimension can be accessed in this fashion as |
| well with <b>BOOST_PP_RELATIVE_START</b> and <b>BOOST_PP_RELATIVE_FINISH</b>. |
| The flags of a relative dimension can be accessed with <b>BOOST_PP_RELATIVE_FLAGS</b>. |
| </div> |
| <h4> |
| Relativity |
| </h4> |
| <div> |
| I mentioned earlier that there is a reason that there are two ways to |
| parametize the mechanism. The reason is dimensional abstraction. In |
| certain situations the dimension is unknown by the code that is being |
| iterated--possibly because the code is reused at multiple, different |
| dimensions. If that code needs to iterate again, it has to define the |
| right parameters (based on the dimension) for the mechanism to consume. |
| </div> |
| <div> |
| All of the macro state maintained by the mechanism can be referred to in an |
| indirect way relative to a dimension. This is the purpose of the <b>BOOST_PP_RELATIVE_</b> |
| accessors. |
| </div> |
| <div> |
| Likewise, the user-defined <i>named external arguments</i> can be defined this |
| way as well--<i>except</i> the name of the file to iterate. Because the |
| lower and upper boundaries are <i>evaluated</i> by the mechanism, the |
| implementation no longer needs the macro <b>BOOST_PP_ITERATION_LIMITS</b>, and |
| the identifier can be reused for each dimension of iteration. |
| </div> |
| <div> |
| Unfortunately, the filename is a different story. The library has no way |
| to evaluate the quoted (or angle-bracketed) text. Therefore, it has to |
| use a different macro for each dimension. That is the purpose of the <b>BOOST_PP_FILENAME_<i>x</i></b> |
| macros. They exist to isolate the only non-abstractable piece of data |
| required by the mechanism. |
| </div> |
| <div> |
| In order to define the filename in an abstract fashion, you need to do |
| something like this: |
| </div> |
| <div class="code"> |
| <pre> |
| #define UNIQUE_TO_FILE "some_file.h" |
| |
| #if BOOST_PP_ITERATION_DEPTH() == 0 |
| #define BOOST_PP_FILENAME_1 UNIQUE_TO_FILE |
| #elif BOOST_PP_ITERATION_DEPTH() == 1 |
| #define BOOST_PP_FILENAME_2 UNIQUE_TO_FILE |
| #elif BOOST_PP_ITERATION_DEPTH() == 2 |
| #define BOOST_PP_FILENAME_3 UNIQUE_TO_FILE |
| |
| // ... up to BOOST_PP_LIMIT_ITERATION_DIM |
| |
| #endif |
| </pre> |
| </div> |
| <div> |
| The intent is to avoid having to do this for anything but the filename. |
| If this needs to be done more than once in a file (<b>BOOST_PP_FILENAME_<i>x</i></b> |
| is undefined by the mechanism after it is used.), consider using a separate |
| file to make the proper definition: |
| </div> |
| <div class="code"> |
| <pre> |
| # // detail/define_file_h.h |
| # ifndef FILE_H |
| # error FILE_H is not defined |
| # endif |
| # |
| # if BOOST_PP_ITERATION_DEPTH() == 0 |
| # define BOOST_PP_FILENAME_1 FILE_H |
| # elif BOOST_PP_ITERATION_DEPTH() == 1 |
| # define BOOST_PP_FILENAME_2 FILE_H |
| # elif BOOST_PP_ITERATION_DEPTH() == 2 |
| # define BOOST_PP_FILENAME_3 FILE_H |
| # elif BOOST_PP_ITERATION_DEPTH() == 3 |
| # define BOOST_PP_FILENAME_4 FILE_H |
| # elif BOOST_PP_ITERATION_DEPTH() == 4 |
| # define BOOST_PP_FILENAME_5 FILE_H |
| # else |
| # error unsupported iteration dimension |
| # endif |
| </pre> |
| </div> |
| <div> |
| And then use it like this.... |
| </div> |
| <div class="code"> |
| <pre> |
| // file.h |
| #if !BOOST_PP_IS_ITERATING |
| |
| #ifndef FILE_H |
| #define FILE_H "file.h" |
| |
| #define BOOST_PP_ITERATION_LIMITS (1, 10) |
| #include "detail/define_file_h.h" |
| |
| ??=include BOOST_PP_ITERATE() |
| |
| #endif // FILE_H |
| |
| #else |
| // iterated portion |
| #endif |
| </pre> |
| </div> |
| <div> |
| With a little effort like this, it is possible to maintain the abstraction |
| without the code bloat that would otherwise be required. Unfortunately, |
| this is not a completely general solution as it would need to be done for each |
| unique filename, but it is better than nothing. |
| </div> |
| <h4> |
| Conclusion |
| </h4> |
| <div> |
| That about covers the facilities that are available from the mechanism. |
| Using these facilities, let's implement a <code>function_traits</code> template |
| to demonstrate a full-fledge use of the mechanism. |
| </div> |
| <h4> |
| Function Traits - An Involved Example |
| </h4> |
| <div> |
| Implementing a comprehensive <code>function_traits</code> template metafunction |
| requires the use of every major part of the file iteration mechanism. |
| </div> |
| <div> |
| (This example makes no attempt of work around compiler deficiencies and exists |
| only to illustrate the mechanism.) |
| </div> |
| <div> |
| The result should have the following features: |
| </div> |
| <ul> |
| <li> |
| return type</li> |
| <li> |
| number and types of parameters</li> |
| <li> |
| whether or not the type is a pointer-to-function, reference-to-function, |
| pointer-to-member-function, or a plain function type</li> |
| <li> |
| whether the type has an ellipsis</li> |
| <li> |
| if not a pointer-to-member-function, the equivalent pointer-to-function, |
| reference-to-function, and function type</li> |
| <li> |
| otherwise, the pointer-to-member type, the class type to which it refers, and |
| whether it is const and/or volatile qualified</li> |
| </ul> |
| <div> |
| There are a myriad of ways that this can be implemented. I'll give a |
| brief summary here of what is happening in the implementation below. |
| </div> |
| <div> |
| The implementation inherently has to deal with function arity. Therefore, |
| at minimum, we need to iterate over function arities and define partial |
| specializations of the primary template <code>function_traits</code>. The |
| situation is further complicated by variadic functions (i.e. functions with an |
| ellipsis). Therefore, for every arity, we need a variadic version as |
| well. |
| </div> |
| <div> |
| We also need to handle pointers-to-member-functions. This implies that we |
| have to handle not just arity and variadics, but also cv-qualifications. |
| </div> |
| <div> |
| For the sake of clarity, the implementation below handles function types and |
| pointers-to-member-functions separately. They could be merged, but the |
| result would be significantly messier. |
| </div> |
| <div> |
| To handle function types, the implementation below iterates over function |
| arities. For each arity, it iterates over each parameter to provide |
| access to each individually. It then re-includes itself to define a |
| variadic specialization of the same arity. It performs the rough |
| equivalent of the following pseudo-code: |
| </div> |
| <div class="code"> |
| <pre> |
| void make_spec(int i, bool variadic) { |
| :open function_traits<i, variadic> |
| for (int j = 0; j < i; ++j) { |
| :parameter<j> |
| } |
| :close |
| if (!variadic) { |
| make_spec(i, true); |
| } |
| return; |
| } |
| |
| void function_types(int max_arity) { |
| for (int i = 0; i <= max_arity; ++i) { |
| make_spec(i, false); |
| } |
| return; |
| } |
| </pre> |
| </div> |
| <div> |
| The implementation of pointers-to-member-functions is a bit different. |
| First, it iterates over cv-qualifiers. For each cv-qualifier, it iterates |
| over function arities. For each function arity, it iterates again over |
| each parameter. It then re-includes itself to define a variadic |
| specialization of the same arity.... |
| </div> |
| <div class="code"> |
| <pre> |
| void make_spec(int j, const char* cv, bool variadic) { |
| :open function_traits<j, cv, variadic> |
| for (int k = 0; k < j; ++k) { |
| parameter<k> |
| } |
| :close |
| if (!variadic) { |
| make_spec(j, cv, true); |
| } |
| return; |
| } |
| |
| void gen_arities(const char* cv, int max_arity) { |
| for (int j = 0; j <= max_arity; ++j) { |
| make_spec(j, cv, false); |
| } |
| return; |
| } |
| |
| void pointers_to_members(int max_arity) { |
| static const char* cv_qualifiers[] = { "", "const", "volatile", "const volatile" }; |
| for (int i = 0; i < 4; ++i) { |
| gen_arities(cv_qualifiers[i], max_arity); |
| } |
| return; |
| } |
| </pre> |
| </div> |
| <div> |
| Here is the complete implementation. This example represents the power of |
| the file iteration mechanism as well as the library in general, so follow it |
| carefully if you wish to fully understand what the mechanism does.... |
| </div> |
| <div class="code"> |
| <pre> |
| // function_traits.hpp |
| |
| #if !BOOST_PP_IS_ITERATING |
| |
| #ifndef FUNCTION_TRAITS_HPP |
| #define FUNCTION_TRAITS_HPP |
| |
| #include <boost/preprocessor/cat.hpp> |
| #include <boost/preprocessor/facilities/apply.hpp> |
| #include <boost/preprocessor/iteration/iterate.hpp> |
| #include <boost/preprocessor/iteration/self.hpp> |
| #include <boost/preprocessor/repetition/enum_params.hpp> |
| #include <boost/preprocessor/repetition/enum_trailing_params.hpp> |
| #include <boost/preprocessor/tuple/elem.hpp> |
| |
| // enable user-expansion |
| #ifndef FUNCTION_TRAITS_MAX_ARITY |
| #define FUNCTION_TRAITS_MAX_ARITY 15 |
| #endif |
| |
| namespace detail { |
| |
| // avoid replication of "default" values |
| struct function_traits_base { |
| static const bool is_plain = false; |
| static const bool is_pointer = false; |
| static const bool is_reference = false; |
| static const bool is_member = false; |
| }; |
| |
| } // detail |
| |
| // no definition |
| template<class> struct function_traits; |
| |
| // extract ellipsis state |
| #define ELLIPSIS(n) \ |
| BOOST_PP_APPLY( \ |
| BOOST_PP_TUPLE_ELEM(2, n, ELLIPSIS_I) \ |
| ) \ |
| /**/ |
| |
| // iterate over function arities for function types |
| #define BOOST_PP_ITERATION_PARAMS_1 \ |
| (4, (0, FUNCTION_TRAITS_MAX_ARITY, "function_traits.hpp", 0)) \ |
| /**/ |
| ??=include BOOST_PP_ITERATE() |
| |
| // obtain a cv-qualifier by index |
| #define QUALIFIER(n) \ |
| BOOST_PP_APPLY( \ |
| BOOST_PP_TUPLE_ELEM( \ |
| 4, n, \ |
| (BOOST_PP_NIL, (const), (volatile), (const volatile)) \ |
| ) \ |
| ) \ |
| /**/ |
| |
| // iterate over cv-qualifiers for pointers-to-members |
| #define BOOST_PP_ITERATION_PARAMS_1 \ |
| (4, (0, 3, "function_traits.hpp", 1)) \ |
| /**/ |
| ??=include BOOST_PP_ITERATE() |
| |
| // remove temporary macros |
| #undef QUALIFIER |
| #undef ELLIPSIS |
| |
| // overriding jumper for pointers-to-functions |
| template<class T> struct function_traits<T*> : function_traits<T> { |
| static const bool is_plain = false; |
| static const bool is_pointer = true; |
| }; |
| |
| // overriding jumper for references-to-functions |
| template<class T> struct function_traits<T&> : function_traits<T> { |
| static const bool is_plain = false; |
| static const bool is_reference = true; |
| }; |
| |
| // eof |
| #endif // FUNCTION_TRAITS_HPP |
| |
| // specializations for function types |
| #elif BOOST_PP_ITERATION_DEPTH() == 1 \ |
| && BOOST_PP_ITERATION_FLAGS() == 0 \ |
| /**/ |
| |
| // define ellipsis state |
| #if BOOST_PP_IS_SELFISH |
| #define ELLIPSIS_I ((true), (...)) |
| #else |
| #define ELLIPSIS_I ((false), BOOST_PP_NIL) |
| #endif |
| |
| #define N BOOST_PP_ITERATION() |
| |
| template<class R BOOST_PP_ENUM_TRAILING_PARAMS(N, class T)> |
| struct function_traits<R (BOOST_PP_ENUM_PARAMS(N, T) ELLIPSIS(1))> |
| : detail::function_traits_base { |
| static const bool is_plain = true; |
| typedef R function_type(BOOST_PP_ENUM_PARAMS(N, T) ELLIPSIS(1)); |
| typedef function_type* pointer_type; |
| typedef function_type& reference_type; |
| static const bool has_ellipsis = ELLIPSIS(0); |
| typedef R return_type; |
| static const int parameter_count = N; |
| template<int, class D = int> struct parameter; |
| #if N |
| // iterate over parameters |
| #define BOOST_PP_ITERATION_PARAMS_2 \ |
| (3, (0, N - 1, "function_traits.hpp")) \ |
| /**/ |
| ??=include BOOST_PP_ITERATE() |
| #endif |
| }; |
| |
| #undef N |
| #undef ELLIPSIS_I |
| |
| // re-include this section for an ellipsis variant |
| #if !BOOST_PP_IS_SELFISH |
| #define BOOST_PP_INDIRECT_SELF "function_traits.hpp" |
| ??=include BOOST_PP_INCLUDE_SELF() |
| #endif |
| |
| // iteration over cv-qualifiers |
| #elif BOOST_PP_ITERATION_DEPTH() == 1 \ |
| && BOOST_PP_ITERATION_FLAGS() == 1 \ |
| /**/ |
| |
| #define BOOST_PP_ITERATION_PARAMS_2 \ |
| (3, (0, FUNCTION_TRAITS_MAX_ARITY, "function_traits.hpp")) \ |
| /**/ |
| ??=include BOOST_PP_ITERATE() |
| |
| // generate specializations for pointers-to-members |
| #elif BOOST_PP_ITERATION_DEPTH() == 2 \ |
| && BOOST_PP_FRAME_FLAGS(1) == 1 \ |
| |
| // define ellipsis state |
| #if BOOST_PP_IS_SELFISH |
| #define ELLIPSIS_I ((true), (...)) |
| #else |
| #define ELLIPSIS_I ((false), BOOST_PP_NIL) |
| #endif |
| |
| #define N BOOST_PP_ITERATION() |
| #define Q QUALIFIER(BOOST_PP_FRAME_ITERATION(1)) |
| |
| template<class R, class O BOOST_PP_ENUM_TRAILING_PARAMS(N, class T)> |
| struct function_traits<R (O::*)(BOOST_PP_ENUM_PARAMS(N, T) ELLIPSIS(1)) Q> |
| : detail::function_traits_base { |
| static const bool is_member = true; |
| typedef R (O::* pointer_to_member_type)(BOOST_PP_ENUM_PARAMS(N, T) ELLIPSIS(1)) Q; |
| typedef O class_type; |
| typedef Q O qualified_class_type; |
| static const bool has_ellipsis = ELLIPSIS(0); |
| static const bool is_const = |
| BOOST_PP_FRAME_ITERATION(1) == 1 || BOOST_PP_FRAME_ITERATION(1) == 3; |
| static const bool is_volatile = |
| BOOST_PP_FRAME_ITERATION(1) == 2 || BOOST_PP_FRAME_ITERATION(1) == 3; |
| typedef R return_type; |
| static const int parameter_count = N; |
| template<int, class D = int> struct parameter; |
| #if N |
| // iterate over parameters |
| #define BOOST_PP_ITERATION_PARAMS_3 \ |
| (3, (0, N - 1, "function_traits.hpp")) \ |
| /**/ |
| ??=include BOOST_PP_ITERATE() |
| #endif |
| }; |
| |
| #undef Q |
| #undef N |
| #undef ELLIPSIS_I |
| |
| // re-include this section for an ellipsis variant |
| #if !BOOST_PP_IS_SELFISH |
| #define BOOST_PP_INDIRECT_SELF "function_traits.hpp" |
| ??=include BOOST_PP_INCLUDE_SELF() |
| #endif |
| |
| // parameter specializations |
| #else |
| |
| #define X BOOST_PP_ITERATION() |
| |
| template<class D> struct parameter<X, D> { |
| typedef BOOST_PP_CAT(T, X) type; |
| }; |
| |
| #undef X |
| |
| #endif |
| </pre> |
| </div> |
| <div> |
| One problem that still exists is the lack of support for <code>throw</code> specifications. |
| There is no way that we can completely handle it anyway because we cannot |
| partially specialize on <code>throw</code> specifications. However, we |
| could accurately report the "actual" function type, etc., including the <code>throw</code> |
| specification (which the above implementation doesn't do, as it reconstructs |
| those types). If you like, you can figure out how to do that on your own |
| as an exercise. |
| </div> |
| <h4> |
| See Also |
| </h4> |
| <ul> |
| <li> |
| <a href="../ref/iterate.html">BOOST_PP_ITERATE</a></li> |
| </ul> |
| <div class="sig"> |
| - Paul Mensonides |
| </div> |
| <hr size="1"> |
| <div style="margin-left: 0px;"> |
| <i>© Copyright <a href="http://www.housemarque.com" target="_top">Housemarque Oy</a> 2002</i> |
| </br><i>© Copyright Paul Mensonides 2002</i> |
| </div> |
| <div style="margin-left: 0px;"> |
| <p><small>Distributed under the Boost Software License, Version 1.0. (See |
| accompanying file <a href="../../../../LICENSE_1_0.txt">LICENSE_1_0.txt</a> or |
| copy at <a href= |
| "http://www.boost.org/LICENSE_1_0.txt">www.boost.org/LICENSE_1_0.txt</a>)</small></p> |
| </div> |
| </body> |
| </html> |