123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044 |
- <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>
|