forked from boostorg/preprocessor
922 lines
31 KiB
HTML
922 lines
31 KiB
HTML
![]() |
<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>Related Topics</h4>
|
||
|
<ul>
|
||
|
<li><a href="choosing_repetition.html">Choosing Between Repetition Constructs</a></li>
|
||
|
</ul>-->
|
||
|
<h4>See Also</h4>
|
||
|
<ul>
|
||
|
<li><a href="../ref/iterate.html">BOOST_PP_ITERATE</a></li>
|
||
|
</ul>
|
||
|
<div class="sig">- Paul Mensonides</div>
|
||
|
</body>
|
||
|
</html>
|