mirror of
https://github.com/boostorg/preprocessor.git
synced 2025-07-18 23:12:07 +02:00
lib cleanup
[SVN r15693]
This commit is contained in:
146
doc/topics/evaluated_slots.html
Normal file
146
doc/topics/evaluated_slots.html
Normal file
@ -0,0 +1,146 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>evaluated_slots.html</title>
|
||||
<link rel="stylesheet" type="text/css" href="../styles.css">
|
||||
</head>
|
||||
<body>
|
||||
<h4>Evaluated Slots</h4>
|
||||
<div>
|
||||
The evaluated slot mechanism is a tool to fully evaluate a constant integral expression and avoid the lazy evaluation normally performed by the preprocessor.
|
||||
</div>
|
||||
<h4>Tutorial</h4>
|
||||
<div>
|
||||
In order to understand the use of such a mechanism, I will start with a simple file-iteration example.
|
||||
Consider the following scenario....
|
||||
</div>
|
||||
<div class ="code"><pre>
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
for (int j = 0; j < i; ++j) {
|
||||
// ... use i and j
|
||||
}
|
||||
}
|
||||
</pre></div>
|
||||
<div>
|
||||
The above is a simple runtime model of the following multidimensional file-iteration....
|
||||
</div>
|
||||
<div class="code"><pre>
|
||||
// file.hpp
|
||||
#if !BOOST_PP_IS_ITERATING
|
||||
#ifndef FILE_HPP_
|
||||
#define FILE_HPP_
|
||||
|
||||
#include <boost/preprocessor/iteration/iterate.hpp>
|
||||
|
||||
#define BOOST_PP_ITERATION_PARAMS_1 (3, (0, 9, "file.hpp"))
|
||||
#include BOOST_PP_ITERATE()
|
||||
|
||||
#endif // FILE_HPP_
|
||||
#elif BOOST_PP_ITERATION_DEPTH() == 1
|
||||
#define I BOOST_PP_ITERATION()
|
||||
|
||||
#define BOOST_PP_ITERATION_PARAMS_2 (3, (0, I, "file.hpp"))
|
||||
#include BOOST_PP_ITERATE()
|
||||
|
||||
#undef I
|
||||
#elif BOOST_PP_ITERATION_DEPTH() == 2
|
||||
#define J BOOST_PP_ITERATION()
|
||||
|
||||
// use I and J
|
||||
|
||||
#undef J
|
||||
#endif
|
||||
</pre></div>
|
||||
<div>
|
||||
There is a problem with the code above.
|
||||
The writer expected <i>I</i> to refer the previous iteration frame.
|
||||
However, that is not the case.
|
||||
When the user refers to <i>I</i>, he is actually referring to <b>BOOST_PP_ITERATION</b>(),
|
||||
not the value of <b>BOOST_PP_ITERATION</b>() at the point of definition.
|
||||
Instead, it refers to exactly the same value to which <i>J</i> refers.
|
||||
</div>
|
||||
<div>
|
||||
The problem is that the preprocessor always evaluates everything with lazy evaluation.
|
||||
To solve the problem, we need <i>I</i> to be <i>evaluated</i> here:
|
||||
</div>
|
||||
<div class="code"><pre>
|
||||
// ...
|
||||
#elif BOOST_PP_ITERATION_DEPTH() == 1
|
||||
#define I BOOST_PP_ITERATION()
|
||||
// ...
|
||||
</pre></div>
|
||||
<div>
|
||||
Fortunately, the library offers a mechanism to do just that: evaluated slots.
|
||||
The following code uses this mechanism to "fix" the example above...
|
||||
</div>
|
||||
<div class="code"><pre>
|
||||
// ...
|
||||
#elif BOOST_PP_ITERATION_DEPTH() == 1
|
||||
#define BOOST_PP_VALUE BOOST_PP_ITERATION()
|
||||
#include BOOST_PP_ASSIGN_SLOT(1)
|
||||
#define I BOOST_PP_SLOT(1)
|
||||
// ...
|
||||
</pre></div>
|
||||
<div>
|
||||
There are two steps to the assignment of an evaluated slot.
|
||||
First, the user must define the <i>named external argument</i> <b>BOOST_PP_VALUE</b>.
|
||||
This value must be an integral constant expression.
|
||||
Second, the user must <i>include</i> <b>BOOST_PP_ASSIGN_SLOT</b>(<i>x</i>), where <i>x</i> is the particular slot to be assigned to (<i>1</i> to <b>BOOST_PP_LIMIT_SLOT_COUNT</b>).
|
||||
This will evaluate <b>BOOST_PP_VALUE</b> and assign the result to the slot at index <i>x</i>.
|
||||
</div>
|
||||
<div>
|
||||
To retrieve a slot's value, the user must use <b>BOOST_PP_SLOT</b>(<i>x</i>).
|
||||
</div>
|
||||
<div>
|
||||
In the case above, <i>I</i> is <i>still</i> lazily evaluated.
|
||||
However, it now evaluates to <b>BOOST_PP_SLOT</b>(<i>1</i>).
|
||||
This value <i>will not change</i> unless there is a subsequent call to <b>BOOST_PP_ASSIGN_SLOT</b>(<i>1</i>).
|
||||
</div>
|
||||
<h4>Advanced Techniques</h4>
|
||||
<div>
|
||||
The slot mechanism can also be used to perform calculations:
|
||||
</div>
|
||||
<div class="code"><pre>
|
||||
#include <iostream>
|
||||
|
||||
#include <boost/preprocessor/slot/slot.hpp>
|
||||
#include <boost/preprocessor/stringize.hpp>
|
||||
|
||||
#define X() 4
|
||||
|
||||
#define BOOST_PP_VALUE 1 + 2 + 3 + X()
|
||||
#include BOOST_PP_ASSIGN_SLOT(1)
|
||||
|
||||
#undef X
|
||||
|
||||
int main(void) {
|
||||
std::cout
|
||||
<< BOOST_PP_STRINGIZE(BOOST_PP_SLOT(1))
|
||||
<< &std::endl;
|
||||
return 0;
|
||||
}
|
||||
</pre></div>
|
||||
<div>
|
||||
In essence, anything that can be evaluated in an #if (or #elif) preprocessor directive is available <i>except</i> the <i>defined</i> operator.
|
||||
</div>
|
||||
<div>
|
||||
It is even possible to use a particular slot itself while reassigning it:
|
||||
</div>
|
||||
<div class="code"><pre>
|
||||
#define BOOST_PP_VALUE 20
|
||||
#include BOOST_PP_ASSIGN_SLOT(1)
|
||||
|
||||
#define BOOST_PP_VALUE 2 * BOOST_PP_SLOT(1)
|
||||
#include BOOST_PP_ASSIGN_SLOT(1)
|
||||
|
||||
BOOST_PP_SLOT(1) // 40
|
||||
</pre></div>
|
||||
<h4>See Also</h4>
|
||||
<ul>
|
||||
<li><a href="../ref/assign_slot.html">BOOST_PP_ASSIGN_SLOT</a></li>
|
||||
<li><a href="../ref/limit_slot_count.html">BOOST_PP_LIMIT_SLOT_COUNT</a></li>
|
||||
<li><a href="../ref/slot.html">BOOST_PP_SLOT</a></li>
|
||||
<li><a href="../ref/value.html">BOOST_PP_VALUE</a></li>
|
||||
</ul>
|
||||
<div class="sig">- Paul Mensonides</div>
|
||||
</body>
|
||||
</html>
|
921
doc/topics/file_iteration.html
Normal file
921
doc/topics/file_iteration.html
Normal file
@ -0,0 +1,921 @@
|
||||
<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>
|
129
doc/topics/incompatible.html
Normal file
129
doc/topics/incompatible.html
Normal file
@ -0,0 +1,129 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>incompatible.html</title>
|
||||
<link rel="stylesheet" type="text/css" href="../styles.css">
|
||||
</head>
|
||||
<body>
|
||||
<h4>Incompatibilities</h4>
|
||||
<div>
|
||||
There are several incompatibilities with the previous Boost release (1.28).
|
||||
These fall into roughly three categories:
|
||||
</div>
|
||||
<ul>
|
||||
<li>the horizontal repetition primitives based on <b>BOOST_PP_REPEAT</b></li>
|
||||
<li>the reentrancy syntax</li>
|
||||
<li><i>list</i> folding</li>
|
||||
</ul>
|
||||
<h4>Repetition Targets</h4>
|
||||
<div>
|
||||
First, and probably the most commonly used, is the target macros passed into <b>BOOST_PP_REPEAT</b> and the horizontal repetition contructs that use <b>BOOST_PP_REPEAT</b>.
|
||||
This includes all of the <b>BOOST_PP_REPEAT_</b>* primitives and all of the <b>BOOST_PP_ENUM_</b>* primitives that require a target macro.
|
||||
</div>
|
||||
<div>
|
||||
The incompatiblity is trivial, but it will require that the source be updated.
|
||||
</div>
|
||||
<div>
|
||||
These target macros must now except a <i>third</i> parameter.
|
||||
This extra parameter becomes the <i>first</i> parameter in every target macro.
|
||||
It represents the next repetition dimension and brings <b>BOOST_PP_REPEAT</b> inline with rest of the library.
|
||||
</div>
|
||||
<div>
|
||||
So, what once was:
|
||||
</div>
|
||||
<div class="code">
|
||||
#define <i>macro</i>(<i>n</i>, <i>data</i>) ...<br>
|
||||
<b>BOOST_PP_REPEAT</b>(<i>5</i>, <i>macro</i>, <i>data</i>)
|
||||
</div>
|
||||
<div>
|
||||
...is now:
|
||||
</div>
|
||||
<div class="code">
|
||||
#define <i>macro</i>(<i>z</i>, <i>n</i>, <i>data</i>) ...<br>
|
||||
<b>BOOST_PP_REPEAT</b>(<i>5</i>, <i>macro</i>, <i>data</i>)
|
||||
</div>
|
||||
<div>
|
||||
This parameter can be used for highly efficient reentrance into the <b>BOOST_PP_REPEAT</b> mechanism.
|
||||
However, it is not necessary to use it as the library can automatically detect the next available repetition dimension.
|
||||
</div>
|
||||
<h4>Dimensional Ordering</h4>
|
||||
<div>
|
||||
Because of this detection, however, it is unsafe to use <b>BOOST_PP_REPEAT_1ST</b>, <b>BOOST_PP_REPEAT_2ND</b>, and <b>BOOST_PP_REPEAT_3RD</b> out of order.
|
||||
These macros bypass the <i>automatic-recursion</i> mechanism, and the <i>automatic-recursion</i> mechanism relies on macros being used in the proper order.
|
||||
To clarify, if you use these bypass macros, the outer-most repetition <i>must</i> be <b>BOOST_PP_REPEAT_1ST</b>, then <b>BOOST_PP_REPEAT_2ND</b>, and finally <b>BOOST_PP_REPEAT_3RD</b>.
|
||||
Any other usage is not supported by the library.
|
||||
Sometimes it may work, and other times it won't.
|
||||
</div>
|
||||
<h4>Reentrancy Syntax</h4>
|
||||
<div>
|
||||
<i>Automatic-recursion</i> brings with it another issue as well. Previously, the reentrancy syntax for <b>BOOST_PP_WHILE</b> (and similarly for <b>BOOST_PP_FOR</b>) was:
|
||||
</div>
|
||||
<div class="code">
|
||||
<b>BOOST_PP_WHILE</b> ## <i>d</i>(<i>pred</i>, <i>op</i>, <i>state</i>)
|
||||
</div>
|
||||
<div>
|
||||
...or:
|
||||
</div>
|
||||
<div class="code">
|
||||
<b>BOOST_PP_CAT</b>(<b>BOOST_PP_WHILE</b>, <i>d</i>)(<i>pred</i>, <i>op</i>, <i>state</i>)
|
||||
</div>
|
||||
<div>
|
||||
Under the <i>automatic-recursion</i> model, the <b>BOOST_PP_CAT</b> version breaks.
|
||||
This is because <b>BOOST_PP_CAT</b> allows its arguments to expand prior to concatenation,
|
||||
and <b>BOOST_PP_WHILE</b> is a macro that expands without arguments.
|
||||
The library makes it appear that it takes three parameters, but that is the trick of <i>automatic-recursion</i>.
|
||||
It works similarly to the following:
|
||||
</div>
|
||||
<div class="code">
|
||||
#define A(x, y) ...<br>
|
||||
#define B A<br>
|
||||
// ...<br>
|
||||
B(2, 3)
|
||||
</div>
|
||||
<div>
|
||||
The syntax makes it look like the <i>B</i> macro above takes two arguments, but it doesn't.
|
||||
The <i>automatic-recursion</i> mechanism works in this fashion, except that the "<i>B</i>" macro deduces the next available "<i>A</i>" macro.
|
||||
</div>
|
||||
<div>
|
||||
Because some preprocessors are still slow, direct reentrancy (sans <i>automatic-recursion</i>) is still necessary in non-trivial cases.
|
||||
Consequently, the library uses a new syntax to handle reentrancy:
|
||||
</div>
|
||||
<div class="code">
|
||||
<b>BOOST_PP_FOR_</b> ## <i>r</i>(<i>state</i>, <i>pred</i>, <i>op</i>, <i>macro</i>)<br>
|
||||
<b>BOOST_PP_REPEAT_</b> ## <i>z</i>(<i>count</i>, <i>macro</i>, <i>data</i>)<br>
|
||||
<b>BOOST_PP_WHILE_</b> ## <i>d</i>(<i>pred</i>, <i>op</i>, <i>state</i>)
|
||||
</div>
|
||||
<h4>Folding</h4>
|
||||
<div>
|
||||
Previously, the <b>BOOST_PP_LIST_FOLD_RIGHT</b> macros' arguments were the reverse of <b>BOOST_PP_LIST_FOLD_LEFT</b>.
|
||||
Also, the accumulation macro passed into <b>BOOST_PP_LIST_FOLD_RIGHT</b> was called with reversed parameters as well.
|
||||
This discrepancy has been eliminated.
|
||||
</div>
|
||||
<div>
|
||||
To illustrate, <b>BOOST_PP_LIST_FOLD_RIGHT</b> used to be used like this:
|
||||
</div>
|
||||
<div class="code">
|
||||
#define <i>macro</i>(<i>d</i>, <u><i>elem</i></u>, <u><i>state</i></u>)<br>
|
||||
<b>BOOST_PP_LIST_FOLD_RIGHT</b>(<i>macro</i>, <u><i>list</i></u>, <u><i>state</i></u>)
|
||||
</div>
|
||||
<div>
|
||||
This signature has been replaced by...
|
||||
</div>
|
||||
<div class="code">
|
||||
#define <i>macro</i>(<i>d</i>, <u><i>state</i></u>, <u><i>elem</i></u>)<br>
|
||||
<b>BOOST_PP_LIST_FOLD_RIGHT</b>(<i>macro</i>, <u><i>state</i></u>, <u><i>list</i></u>)
|
||||
</div>
|
||||
<h4>Summary</h4>
|
||||
<div>
|
||||
The library has many new features not present in the 1.28 release, and this list does not attempt to enumerate them.
|
||||
This is simply a list of things that <i>must</i> change for code to be compatible with this new release.
|
||||
</div>
|
||||
<h4>See Also</h4>
|
||||
<ul>
|
||||
<li><a href="../ref/for.html">BOOST_PP_FOR</a></li>
|
||||
<li><a href="../ref/list_fold_right.html">BOOST_PP_LIST_FOLD_RIGHT</a></li>
|
||||
<li><a href="../ref/repeat.html">BOOST_PP_REPEAT</a></li>
|
||||
<li><a href="../ref/while.html">BOOST_PP_WHILE</a></li>
|
||||
</ul>
|
||||
<div class="sig">- Paul Mensonides</div>
|
||||
</body>
|
||||
</html>
|
149
doc/topics/local_iteration.html
Normal file
149
doc/topics/local_iteration.html
Normal file
@ -0,0 +1,149 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>local_iteration.html</title>
|
||||
<link rel="stylesheet" type="text/css" href="../styles.css">
|
||||
</head>
|
||||
<body>
|
||||
<h4>Local Iteration</h4>
|
||||
<div>
|
||||
Local iteration is a simple vertical repetition construct.
|
||||
It expands a macro with each number in a user-specified range.
|
||||
Each expansion is on a separate line.
|
||||
</div>
|
||||
<h4>Tutorial</h4>
|
||||
<div>
|
||||
This mechanism requires two pieces of information to operate:
|
||||
a range to iterate over and a macro to expand on each iteration.
|
||||
This information is obtained by the mechanism through two <i>named external arguments</i>.
|
||||
These arguments are specified as user-defined macros named <b>BOOST_PP_LOCAL_LIMITS</b> and <b>BOOST_PP_LOCAL_MACRO</b>.
|
||||
</div>
|
||||
<div>
|
||||
<b>BOOST_PP_LOCAL_LIMITS</b> specifies a 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 macro to be expanded with numbers ranging from <i>0</i> to <i>10</i>,
|
||||
<b>BOOST_PP_LOCAL_LIMITS</b> would be defined like this:
|
||||
</div>
|
||||
<div class="code"><pre>
|
||||
#define BOOST_PP_LOCAL_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_LOCAL_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_LOCAL_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_LOCAL_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_LOCAL_LIMITS (A, B)
|
||||
// note: has whitespace ^
|
||||
</pre></div>
|
||||
<div>
|
||||
<b>BOOST_PP_LOCAL_MACRO</b> is the macro that is expanded by the mechanism.
|
||||
This macro is expanded on each iteration with the current number of the iteration.
|
||||
It must defined as a unary macro <i>or</i> result in a macro that can be called with one argument:
|
||||
</div>
|
||||
<div class="code"><pre>
|
||||
#define BOOST_PP_LOCAL_MACRO(n) \
|
||||
template<> struct sample<n> { }; \
|
||||
/**/
|
||||
</pre></div>
|
||||
<div>
|
||||
...or...
|
||||
</div>
|
||||
<div class="code"><pre>
|
||||
#define SAMPLE(n) \
|
||||
template<> struct sample<n> { }; \
|
||||
/**/
|
||||
|
||||
#define BOOST_PP_LOCAL_MACRO SAMPLE
|
||||
</pre></div>
|
||||
<div>
|
||||
Once these two macros are defined, the local iteration is initiated by <i>including</i> <b>BOOST_PP_LOCAL_ITERATE</b>().
|
||||
</div>
|
||||
<div class="code"><pre>
|
||||
??=include BOOST_PP_LOCAL_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>
|
||||
In order to repeat the <code>sample</code> specialization, the pieces must be put together....
|
||||
</div>
|
||||
<div class="code"><pre>
|
||||
#define BOOST_PP_LOCAL_MACRO(n) \
|
||||
template<> struct sample<n> { }; \
|
||||
/**/
|
||||
|
||||
#define BOOST_PP_LOCAL_LIMITS (0, 10)
|
||||
??=include BOOST_PP_LOCAL_ITERATE()
|
||||
</pre></div>
|
||||
<div>
|
||||
This will result in a specialization of <code>sample</code> for each number in the range of <i>0</i> to <i>10</i>.
|
||||
The output will look something like this:
|
||||
</div>
|
||||
<div class="code"><pre>
|
||||
template<> struct sample<0> { };
|
||||
template<> struct sample<1> { };
|
||||
template<> struct sample<2> { };
|
||||
|
||||
// ...
|
||||
|
||||
template<> struct sample<10> { };
|
||||
</pre></div>
|
||||
<div>
|
||||
After the local-iteration is complete, both <b>BOOST_PP_LOCAL_LIMITS</b> and <b>BOOST_PP_LOCAL_MACRO</b> are automatically undefined.
|
||||
If the values need to be retained for a future local-iteration, they must be defined indirectly:
|
||||
</div>
|
||||
<div class="code"><pre>
|
||||
#define LIMITS (0, 10)
|
||||
|
||||
#define SAMPLE(n) \
|
||||
template<> struct sample<n> { }; \
|
||||
/**/
|
||||
|
||||
#define BOOST_PP_LOCAL_LIMITS LIMITS
|
||||
#define BOOST_PP_LOCAL_MACRO(n) SAMPLE(n)
|
||||
|
||||
??=include BOOST_PP_LOCAL_ITERATE()
|
||||
</pre></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/local_iterate.html">BOOST_PP_LOCAL_ITERATE</a></li>
|
||||
<li><a href="../ref/local_limits.html">BOOST_PP_LOCAL_LIMITS</a></li>
|
||||
<li><a href="../ref/local_macro.html">BOOST_PP_LOCAL_MACRO</a></li>
|
||||
</ul>
|
||||
<div class="sig">- Paul Mensonides</div>
|
||||
</body>
|
||||
</html>
|
100
doc/topics/motivation.html
Normal file
100
doc/topics/motivation.html
Normal file
@ -0,0 +1,100 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>motivation.html</title>
|
||||
<link rel="stylesheet" type="text/css" href="../styles.css">
|
||||
</head>
|
||||
<body>
|
||||
<h4>Motivation</h4>
|
||||
<div>
|
||||
The C++ function and template parameter lists are special syntactic constructs, and it is impossible to directly
|
||||
manipulate or generate them using C++ constructs.
|
||||
This leads to unnecessary code repetition.
|
||||
</div>
|
||||
<div>
|
||||
Consider the implementation of the <code>is_function<></code> metafunction is Boost.
|
||||
The implementation uses an overloaded <code>is_function_tester()</code> function that is used for testing if a type is convertible
|
||||
to a pointer to a function.
|
||||
Because of the special treatment of parameter lists, it is not possible to directly match a function with an arbitrary parameter list.
|
||||
Instead, the <code>is_function_tester()</code> must be overloaded for every distinct number of parameters that is to be supported.
|
||||
For example:
|
||||
</div>
|
||||
<div class="code"><pre>
|
||||
template<class R>
|
||||
yes_type is_function_tester(R (*)());
|
||||
|
||||
template<class R, class A0>
|
||||
yes_type is_function_tester(R (*)(A0));
|
||||
|
||||
template<class R, class A0, class A1>
|
||||
yes_type is_function_tester(R (*)(A0, A1));
|
||||
|
||||
template<class R, class A0, class A1, class A2>
|
||||
yes_type is_function_tester(R (*)(A0, A1, A2));
|
||||
|
||||
// ...
|
||||
</pre></div>
|
||||
<div>
|
||||
The need for this kind of repetition occurs particularly frequently while implementing generic components or metaprogramming facilities,
|
||||
but the need also manifests itself in many far simpler situations.
|
||||
</div>
|
||||
<h4>Typical Solutions</h4>
|
||||
<div>
|
||||
Typically the repetition is done manually.
|
||||
Manual code repetition is highly unproductive, but sometimes more readable to the untrained eye.
|
||||
</div>
|
||||
<div>
|
||||
Another solution is to write an external program for generating the repeated code or use some other extra linguistic means such as a smart editor.
|
||||
Unfortunately, using external code generators has many disadvantages:
|
||||
<ul>
|
||||
<li>Writing the generator takes time. (This could be helped by using a standard generator.)</li>
|
||||
<li>It is no longer productive to manipulate C++ code directly.</li>
|
||||
<li>Invoking the generator may be difficult.</li>
|
||||
<li>Automating the invocation of the generator can be difficult in certain environments. (Automatic invocation is desirable for active libraries.)</li>
|
||||
<li>Porting and distributing the generator may be difficult or simply takes precious time.</li>
|
||||
</ul>
|
||||
</div>
|
||||
<h4>What about the preprocessor?</h4>
|
||||
<div>
|
||||
Because C++ comes with a preprocessor, one would assume that it would support these kinds of needs directly.
|
||||
Using the preprocessor in this case is highly desirable because:
|
||||
<ul>
|
||||
<li>The preprocessor is highly portable.</li>
|
||||
<li>The preprocessor is automatically invoked as part of the compilation process.</li>
|
||||
<li>Preprocessor metacode can be directly embedded into the C++ source code.</li>
|
||||
<li>Compilers generally allow viewing or outputting the preprocessed code, which can be used for debugging or to copy and paste the generated code.</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
Most unfortunately, the preprocessor is a very low level preprocessor that specifically does not support repetition or recursive macros.
|
||||
Library support is needed!
|
||||
</div>
|
||||
<div>
|
||||
<i>For detailed information on the capabilities and limitations of the preprocessor, please refer to the C++ standard <a href="bibliography.html#std">[Std]</a>.</i>
|
||||
</div>
|
||||
<h4>The Motivation Example Revisited</h4>
|
||||
<div>
|
||||
Using the primitives of the preprocessor library, the <code>is_function_tester()</code>'s could be implemented like this:
|
||||
</div>
|
||||
<div class="code"><pre>
|
||||
#define IS_FUNCTION_TESTER(Z, N, _) \
|
||||
template<class R BOOST_PP_COMMA_IF(N) BOOST_PP_ENUM_PARAMS(N, class A)> \
|
||||
yes_type is_function_tester(R (*)(BOOST_PP_ENUM_PARAMS(N, A))); \
|
||||
/**/
|
||||
|
||||
BOOST_PP_REPEAT(BOOST_PP_INC(MAX_IS_FUNCTION_TESTER_PARAMS), IS_FUNCTION_TESTER, _)
|
||||
|
||||
#undef IS_FUNCTION_TESTER
|
||||
</pre></div>
|
||||
<div>
|
||||
In order to change the maximum number of function parameters supported, you now simply change the <code>MAX_IS_FUNCTION_TESTER_PARAMS</code> definition and recompile.
|
||||
</div>
|
||||
<hr size="1">
|
||||
<div style="margin-left: 0px;">
|
||||
<i><EFBFBD> Copyright <a href="http://www.housemarque.com" target="_top">Housemarque Oy</a> 2002</i>
|
||||
</div>
|
||||
<div style="margin-left: 0px;">
|
||||
Permission to copy, use, modify, sell and distribute this document is granted provided this copyright notice appears in all copies.
|
||||
This document is provided "as is" without express or implied warranty and with no claim as to its suitability for any purpose.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
124
doc/topics/problems.html
Normal file
124
doc/topics/problems.html
Normal file
@ -0,0 +1,124 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>problems.html</title>
|
||||
<link rel="stylesheet" type="text/css" href="../styles.css">
|
||||
</head>
|
||||
<body>
|
||||
<h4>Known Problems of the C/C++ Preprocessor</h4>
|
||||
<div>
|
||||
Preprocessor metaprogramming is subject to heated discussions.
|
||||
Part of this is caused by bad experiences with dangerous techniques,
|
||||
such as defining inline functions using macros.
|
||||
As a rule of thumb, if you can find a clean and manageable way to do something
|
||||
without the preprocessor, then you should do it that way.
|
||||
</div>
|
||||
<div>
|
||||
Let's survey some of the widely known problems of the preprocessor in a problem/solution format.
|
||||
</div>
|
||||
<h4>Problem #1</h4>
|
||||
<div>
|
||||
The preprocessor does not respect scope, therefore macros can accidentally and sometimes silently replace code.
|
||||
</div>
|
||||
<div>
|
||||
<b>Solution A</b>
|
||||
<div>
|
||||
Use all caps identifiers for macros and only macros.
|
||||
This practically eliminates the possibility that a macro might replace other kinds of code accidentally.
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<b>Solution B</b>
|
||||
<div>
|
||||
Use the local macro idiom:
|
||||
</div>
|
||||
<div class="code"><pre>
|
||||
#define MACRO ...
|
||||
// use MACRO
|
||||
#undef MACRO
|
||||
</pre></div>
|
||||
<div>
|
||||
This makes sure that a macro cannot accidentally replace code outside of the scope of the local macro.
|
||||
</div>
|
||||
<div>
|
||||
A problem with this solution is that the #undef cannot be automated and may be forgotten.
|
||||
Experienced programmers generally write the #undef either immediately before (in time)
|
||||
or immediately after writing the macro definition.
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<b>Solution C</b>
|
||||
<div>
|
||||
Use the unique macro prefix idiom.
|
||||
</div>
|
||||
<div class="code"><pre>
|
||||
#define UMP_MACRO
|
||||
// use UMP_MACRO
|
||||
</pre></div>
|
||||
<div>
|
||||
This makes accidental substitution and collisions highly unlikely.
|
||||
Problems with this solution include:
|
||||
</div>
|
||||
<ul>
|
||||
<li>There can still be naming collisions inside a large project.</li>
|
||||
<li>Macros still pollute the global namespace.</li>
|
||||
</ul>
|
||||
<i>By combining all solutions, whenever possible, the scope problem can be largely avoided.</i>
|
||||
</div>
|
||||
<h4>Problem #2</h4>
|
||||
<div>
|
||||
Preprocessor code is difficult to read.
|
||||
It requires an understanding of the basic process of how the preprocessor recursively expands macros,
|
||||
finding macro definitions, and mentally substituting the parameters of the macro.
|
||||
</div>
|
||||
<div>
|
||||
<b>Solution</b>
|
||||
<div>
|
||||
Any kind of programming requires a basic understanding of how the code is executed.
|
||||
Any parameterization technique, including simple functions and templates requires finding
|
||||
the definition and mentally substituting parameters.
|
||||
</div>
|
||||
<div>
|
||||
However, it is good to know a few techniques:
|
||||
</div>
|
||||
<ul>
|
||||
<li>By using as many local macros as reasonable, the bulk of the searching process can be eliminated.</li>
|
||||
<li>Code browsers and text search tools make it easier to find the definitions.</li>
|
||||
<li>The compiler can be used for generating the preprocessed source code in order to look for bugs.</li>
|
||||
<li>
|
||||
Before turning something into a preprocessor metaprogram, first implement a small scale version
|
||||
of it without the preprocessor.
|
||||
The work bottom-up, replacing hand-written constructs by using the preprocessor.
|
||||
This way you can test the code incrementally.
|
||||
Experienced programmers often skip many stages, but if something proves too complex to write
|
||||
directly, it is always possible to fall back to incremental methods.
|
||||
</li>
|
||||
<li>
|
||||
If you insert a special symbol into the preprocessor code in places where there should be a line break,
|
||||
you can make code readable after preprocessing simply by using a search and replace tool.
|
||||
</li>
|
||||
</ul>
|
||||
<i>An especially important thing to remember is to limit the use of the preprocessor to
|
||||
structured, well-understood, and safe methods.
|
||||
Structure helps to understand complex systems <a href="../bibliography.html#mcconnell">[McConnell]</a>.</i>
|
||||
</div>
|
||||
<h4>Problem #3</h4>
|
||||
<div>
|
||||
"I'd like to see Cpp abolished." - <i>Bjarne Stroustrup</i> in <a href="../bibliography.html#stroustrup">[Stroustrup]</a>.
|
||||
</div>
|
||||
<div>
|
||||
<b>Solution</b>
|
||||
<div>
|
||||
The C/C++ preprocessor will be here for a long time.
|
||||
</div>
|
||||
<i>In practice, preprocessor metaprogramming is far simpler and more portable than template metaprogramming <a href="../bibliography.html#czarnecki">[Czarnecki]</a>.</i>
|
||||
</div>
|
||||
<hr size="1">
|
||||
<div style="margin-left: 0px;">
|
||||
<i><EFBFBD> Copyright <a href="http://www.housemarque.com" target="_top">Housemarque Oy</a> 2002</i>
|
||||
</div>
|
||||
<div style="margin-left: 0px;">
|
||||
Permission to copy, use, modify, sell and distribute this document is granted provided this copyright notice appears in all copies.
|
||||
This document is provided "as is" without express or implied warranty and with no claim as to its suitability for any purpose.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
253
doc/topics/reentrancy.html
Normal file
253
doc/topics/reentrancy.html
Normal file
@ -0,0 +1,253 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>reentrancy.html</title>
|
||||
<link rel="stylesheet" type="text/css" href="../styles.css">
|
||||
</head>
|
||||
<body>
|
||||
<h4>Reentrancy</h4>
|
||||
<div>
|
||||
Macro expansion in the preprocessor is entirely functional.
|
||||
Therefore, there is no iteration.
|
||||
Unfortunately, the preprocessor also disallows recursion.
|
||||
This means that the library must fake iteration or recursion by
|
||||
defining sets of macros that are implemented similarly.
|
||||
</div>
|
||||
<div>
|
||||
To illustrate, here is a simple concatenation macro:
|
||||
</div>
|
||||
<div class="code"><pre>
|
||||
#define CONCAT(a, b) CONCAT_D(a, b)
|
||||
#define CONCAT_D(a, b) a ## b
|
||||
|
||||
CONCAT(a, CONCAT(b, c)) // abc
|
||||
</pre></div>
|
||||
<div>
|
||||
This is fine for a simple case like the above, but what happens in a scenario like the following:
|
||||
</div>
|
||||
<div class="code"><pre>
|
||||
#define AB(x, y) CONCAT(x, y)
|
||||
|
||||
CONCAT(A, B(p, q)) // CONCAT(p, q)
|
||||
</pre></div>
|
||||
<div>
|
||||
Because there is no recursion, the example above expands to <code>CONCAT(p, q)</code> rather than <code>pq</code>.
|
||||
</div>
|
||||
<div>
|
||||
There are only two ways to "fix" the above.
|
||||
First, it can be documented that <code>AB</code> uses <code>CONCAT</code> and disallow usage similar to the above.
|
||||
Second, multiple concatenation macros can be provided....
|
||||
</div>
|
||||
<div class="code"><pre>
|
||||
#define CONCAT_1(a, b) CONCAT_1_D(a, b)
|
||||
#define CONCAT_1_D(a, b) a ## b
|
||||
|
||||
#define CONCAT_2(a, b) CONCAT_2_D(a, b)
|
||||
#define CONCAT_2_D(a, b) a ## b
|
||||
|
||||
#define AB(x, y) CONCAT_2(x, y)
|
||||
|
||||
CONCAT_1(A, B(p, q)) // pq
|
||||
</pre></div>
|
||||
<div>
|
||||
This solves the problem.
|
||||
However, it is now necessary to know that <code>AB</code> uses, not only <i>a</i> concatenation macro,
|
||||
but <code>CONCAT_2</code> specifically.
|
||||
</div>
|
||||
<div>
|
||||
A better solution is to abstract <i>which</i> concatenation macro is used....
|
||||
</div>
|
||||
<div class="code"><pre>
|
||||
#define AB(c, x, y) CONCAT_ ## c(x, y)
|
||||
|
||||
CONCAT_1(A, B(2, p, q)) // pq
|
||||
</pre></div>
|
||||
<div>
|
||||
This is an example of <i>generic reentrance</i>, in this case, into a fictional set of concatenation macros.
|
||||
The <code>c</code> parameter represents the "state" of the concatenation construct,
|
||||
and as long as the user keeps track of this state, <code>AB</code> can be used inside of a concatenation macro.
|
||||
</div>
|
||||
<div>
|
||||
The library has the same choices.
|
||||
It either has to disallow a construct being inside itself or provide multiple, equivalent definitions of a construct
|
||||
and provide a uniform way to <i>reenter</i> that construct.
|
||||
There are several contructs that <i>require</i> recursion (such as <b>BOOST_PP_WHILE</b>).
|
||||
Consequently, the library chooses to provide several sets of macros with mechanisms to reenter the set at a macro
|
||||
that has not already been used.
|
||||
</div>
|
||||
<div>
|
||||
In particular, the library must provide reentrance for <b>BOOST_PP_FOR</b>, <b>BOOST_PP_REPEAT</b>, and <b>BOOST_PP_WHILE</b>.
|
||||
There are two mechanisms that are used to accomplish this: state parameters (like the above concatenation example) and <i>automatic recursion</i>.
|
||||
</div>
|
||||
<h4>State Parameters</h4>
|
||||
<div>
|
||||
Each of the above constructs (<b>BOOST_PP_FOR</b>, <b>BOOST_PP_REPEAT</b>, and <b>BOOST_PP_WHILE</b>) has an associated state.
|
||||
This state provides the means to reenter the respective construct.
|
||||
</div>
|
||||
<div>
|
||||
Several user-defined macros are passed to each of these constructs (for use as predicates, operations, etc.).
|
||||
Every time a user-defined macro is invoked, it is passed the current state of the construct that invoked it so that the macro can reenter
|
||||
the respective set if necessary.
|
||||
</div>
|
||||
<div>
|
||||
These states are used in one of two ways--either by concatenating to or passing to another macro.
|
||||
</div>
|
||||
<div>
|
||||
There are three types of macros that use these state parameters.
|
||||
First, the set itself which is reentered through concatenation.
|
||||
Second, corresponding sets that act like they are a part of the the primary set.
|
||||
These are also reentered through concatenation.
|
||||
And third, macros that internally use the first or second type of macro.
|
||||
These macros take the state as an additional argument.
|
||||
</div>
|
||||
<div>
|
||||
The state of <b>BOOST_PP_WHILE</b> is symbolized by the letter <i>D</i>.
|
||||
Two user-defined macros are passed to <b>BOOST_PP_WHILE</b>--a predicate and an operation.
|
||||
When <b>BOOST_PP_WHILE</b> expands these macros, it passes along its state so that these macros
|
||||
can reenter the <b>BOOST_PP_WHILE</b> set.
|
||||
</div>
|
||||
<div>
|
||||
Consider the following multiplication implementation that illustrates this technique:
|
||||
</div>
|
||||
<div class="code"><pre>
|
||||
// The addition interface macro.
|
||||
// The _D signifies that it reenters
|
||||
// BOOST_PP_WHILE with concatenation.
|
||||
|
||||
#define ADD_D(d, x, y) \
|
||||
BOOST_PP_TUPLE_ELEM( \
|
||||
2, 0, \
|
||||
BOOST_PP_WHILE_ ## d(ADD_P, ADD_O, (x, y)) \
|
||||
) \
|
||||
/**/
|
||||
|
||||
// The predicate that is passed to BOOST_PP_WHILE.
|
||||
// It returns "true" until "y" becomes zero.
|
||||
|
||||
#define ADD_P(d, xy) BOOST_PP_TUPLE_ELEM(2, 1, xy)
|
||||
|
||||
// The operation that is passed to BOOST_PP_WHILE.
|
||||
// It increments "x" and decrements "y" which will
|
||||
// eventually cause "y" to equal zero and therefore
|
||||
// cause the predicate to return "false."
|
||||
|
||||
#define ADD_O(d, xy) \
|
||||
( \
|
||||
BOOST_PP_INC( \
|
||||
BOOST_PP_TUPLE_ELEM(2, 0, xy) \
|
||||
), \
|
||||
BOOST_PP_DEC( \
|
||||
BOOST_PP_TUPLE_ELEM(2, 1, xy) \
|
||||
) \
|
||||
) \
|
||||
/**/
|
||||
|
||||
// The multiplication interface macro.
|
||||
|
||||
#define MUL(x, y) \
|
||||
BOOST_PP_TUPLE_ELEM( \
|
||||
3, 0, \
|
||||
BOOST_PP_WHILE(MUL_P, MUL_O, (0, x, y)) \
|
||||
) \
|
||||
/**/
|
||||
|
||||
// The predicate that is passed to BOOST_PP_WHILE.
|
||||
// It returns "true" until "y" becomes zero.
|
||||
|
||||
#define MUL_P(d, rxy) BOOST_PP_TUPLE_ELEM(3, 2, rxy)
|
||||
|
||||
// The operation that is passed to BOOST_PP_WHILE.
|
||||
// It adds "x" to "r" and decrements "y" which will
|
||||
// eventually cause "y" to equal zero and therefore
|
||||
// cause the predicate to return "false."
|
||||
|
||||
#define MUL_O(d, rxy) \
|
||||
( \
|
||||
ADD_D( \
|
||||
d, /* pass the state on to ADD_D */ \
|
||||
BOOST_PP_TUPLE_ELEM(3, 0, rxy), \
|
||||
BOOST_PP_TUPLE_ELEM(3, 1, rxy) \
|
||||
), \
|
||||
BOOST_PP_TUPLE_ELEM(3, 1, rxy), \
|
||||
BOOST_PP_DEC( \
|
||||
BOOST_PP_TUPLE_ELEM(3, 2, rxy) \
|
||||
) \
|
||||
) \
|
||||
/**/
|
||||
|
||||
MUL(3, 2) // expands to 6
|
||||
</pre></div>
|
||||
<div>
|
||||
There are a couple things to note in the above implementation.
|
||||
First, note how <code>ADD_D</code> reenters <b>BOOST_PP_WHILE</b> using the <i>d</i> state parameter.
|
||||
Second, note how <code>MUL</code>'s operation, which is expanded by <b>BOOST_PP_WHILE</b>, passes the state
|
||||
on to <code>ADD_D</code>.
|
||||
This illustrates state reentrance by both argument and concatenation.
|
||||
</div>
|
||||
<div>
|
||||
For every macro in the library that uses <b>BOOST_PP_WHILE</b>,
|
||||
there is a state reentrant variant.
|
||||
If that variant uses an argument rather than concatenation, it is suffixed by <code>_D</code> to symbolize its
|
||||
method of reentrance.
|
||||
Examples or this include the library's own <b>BOOST_PP_ADD_D</b> and <b>BOOST_PP_MUL_D</b>.
|
||||
If the variant uses concatenation, it is suffixed by an underscore.
|
||||
It is completed by concatenation of the state.
|
||||
This includes <b>BOOST_PP_WHILE</b> itself with <b>BOOST_PP_WHILE_</b> ## <i>d</i> and, for example,
|
||||
<b>BOOST_PP_LIST_FOLD_LEFT</b> with <b>BOOST_PP_LIST_FOLD_LEFT_</b> ## <i>d</i>.
|
||||
</div>
|
||||
<div>
|
||||
The same set of conventions are used for <b>BOOST_PP_FOR</b> and <b>BOOST_PP_REPEAT</b>, but with the letters
|
||||
<i>R</i> and <i>Z</i>, respectively, to symbolize their states.
|
||||
</div>
|
||||
<div>
|
||||
Also note that the above <code>MUL</code> implementation, though not immediately obvious, is using <i>all three</i>
|
||||
types of reentrance.
|
||||
Not only is it using both types of <i>state</i> reentrance, it is also using <i>automatic recursion</i>....
|
||||
</div>
|
||||
<h4>Automatic Recursion</h4>
|
||||
<div>
|
||||
Automatic recursion is a technique that vastly simplifies the use of reentrant constructs.
|
||||
It is used by simply <i>not</i> using any state parameters at all.
|
||||
</div>
|
||||
<div>
|
||||
The <code>MUL</code> example above uses automatic recursion when it uses <b>BOOST_PP_WHILE</b> by itself.
|
||||
In other words, <code>MUL</code> can <i>still</i> be used inside <b>BOOST_PP_WHILE</b> even though it doesn't
|
||||
reenter <b>BOOST_PP_WHILE</b> by concatenating the state to <b>BOOST_PP_WHILE_</b>.
|
||||
</div>
|
||||
<div>
|
||||
To accomplish this, the library uses a "trick."
|
||||
Despite what it looks like, the macro <b>BOOST_PP_WHILE</b> does not take three arguments.
|
||||
In fact, it takes no arguments at all.
|
||||
Instead, the <b>BOOST_PP_WHILE</b> macro expands <i>to</i> a macro that takes three arguments.
|
||||
It simply detects what the next available <b>BOOST_PP_WHILE_</b> ## <i>d</i> macro is and returns it.
|
||||
This detection process is somewhat involved, so I won't go into <i>how</i> it works here,
|
||||
but suffice to say it <i>does</i> work.
|
||||
</div>
|
||||
<div>
|
||||
Using automatic recursion to reenter various sets of macros is obviously much simpler.
|
||||
It completely hides the underlying implementation details.
|
||||
So, if it is so much easier to use, why do the state parameters still exist?
|
||||
The reason is simple as well.
|
||||
When state parameters are used, the state is <i>known</i> at all times.
|
||||
This is not the case when automatic recursion is used.
|
||||
The automatic recursion mechanism has to <i>deduce</i> the state at each point that it is used.
|
||||
This implies a cost in macro complexity that in some situations--notably at deep macro depths--will slow
|
||||
some preprocessors to a crawl.
|
||||
</div>
|
||||
<h4>Conclusion</h4>
|
||||
<div>
|
||||
It is really a tradeoff whether to use state parameters or automatic recursion for reentrancy.
|
||||
The strengths of automatic recursion are ease of use and implementation encapsulation.
|
||||
These come at a performance cost on some preprocessors in some situations.
|
||||
The primary strength of state parameters, on the other hand, is efficiency.
|
||||
Use of the state parameters is the only way to achieve <i>maximum</i> efficiency.
|
||||
This efficiency comes at the cost of both code complexity and exposition of implementation.
|
||||
</div>
|
||||
<h4>See Also</h4>
|
||||
<ul>
|
||||
<li><a href="../ref/for.html">BOOST_PP_FOR</a></li>
|
||||
<li><a href="../ref/repeat.html">BOOST_PP_REPEAT</a></li>
|
||||
<li><a href="../ref/while.html">BOOST_PP_WHILE</a></li>
|
||||
</ul>
|
||||
<div class="sig">- Paul Mensonides</div>
|
||||
</body>
|
||||
</html>
|
336
doc/topics/techniques.html
Normal file
336
doc/topics/techniques.html
Normal file
@ -0,0 +1,336 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>techniques.html</title>
|
||||
<link rel="stylesheet" type="text/css" href="../styles.css">
|
||||
<style>
|
||||
u { font-weight: normal; text-decoration: none; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h4>Techniques</h4>
|
||||
<div>
|
||||
The preprocessor metaprogramming techniques are presented in example format.
|
||||
</div>
|
||||
|
||||
<h4>Example<u> - Use a local macro to avoid small scale repetition.</u></h4>
|
||||
<div class="code"><pre>
|
||||
#define BOOST_PP_DEF(op) /* ..................................... */ \
|
||||
template<class T, int n> \
|
||||
vec<T, n> operator op ## =(vec<T, n> lhs, const vec<T, n>& rhs) { \
|
||||
for (int i = 0; i < n; ++i) { \
|
||||
lhs(i) op ## = rhs(i); \
|
||||
} \
|
||||
} \
|
||||
/**/
|
||||
|
||||
BOOST_PP_DEF(+)
|
||||
BOOST_PP_DEF(-)
|
||||
BOOST_PP_DEF(*)
|
||||
BOOST_PP_DEF(/)
|
||||
|
||||
#undef BOOST_PP_DEF
|
||||
</pre></div>
|
||||
<div>
|
||||
<b>Tip:</b> It is usually okay to use a standard macro name like <code>BOOST_PP_DEF</code> for this kind of code
|
||||
because the macro is both defined and undefined in the immediate site of its use.
|
||||
</div>
|
||||
<div>
|
||||
<b>Tip:</b> It is easier to verify proper use of the line continuation operator when they are aligned.
|
||||
</div>
|
||||
<div>
|
||||
<b>Notes:</b> You can extend this example by defining more and different kinds of operators.
|
||||
Before doing so, consider using the <i>algebraic categories</i> technique introduced in <a href="bibliography.html#barton">[Barton]</a>
|
||||
or a <i>layered architecture</i> (see for instance <a href="bibliography.html#czarnecki">[Czarnecki]</a>).
|
||||
However, at some point you must type the operator tokens <code>*</code>, <code>/</code>, <code>+</code>, <code>-</code>, etc.,
|
||||
because it is impossible to generate them using templates.
|
||||
The resulting <i>categorical repetition</i> of tokens can be eliminated by using preprocessor metaprogramming.
|
||||
</div>
|
||||
|
||||
<h4>Example<u> - Use BOOST_PP_EMPTY as an unused parameter in local macro instantiations.</u></h4>
|
||||
<div class="code"><pre>
|
||||
#define BOOST_PP_DEF(cv) /* ... */ \
|
||||
template<class base> \
|
||||
cv() typename implement_subscript_using_begin_subscript<base>::value_type& \
|
||||
implement_subscript_using_begin_subscript<base>::operator[](index_type i) cv() { \
|
||||
return base::begin()[i]; \
|
||||
} \
|
||||
/**/
|
||||
</pre></div>
|
||||
<div>
|
||||
<b>How:</b> BOOST_PP_EMPTY() expands to nothing and can be used as an unused parameter.
|
||||
</div>
|
||||
<div>
|
||||
<b>Note:</b> BOOST_PP_EMPTY with the () never gets expanded.
|
||||
The () is necessary to invoke a function-like macro.
|
||||
</div>
|
||||
<div>
|
||||
<b>Caveat:</b> You cannot safely use concatenation while using BOOST_PP_EMPTY().
|
||||
</div>
|
||||
<div>
|
||||
<b>Tip:</b> Occasionally, one or two lines are considerably longer than the rest.
|
||||
It can often save some work to <i>not</i> align all the line continuation operators without making the code too unreadable.
|
||||
</div>
|
||||
<div>
|
||||
<b>Tip:</b> Use syntax highlighting on preprocessor metaprogramming macro identifiers such as:
|
||||
<ul>
|
||||
<li>BOOST_PP_DEF</li>
|
||||
<li>BOOST_PP_EMPTY</li>
|
||||
<li>BOOST_PP_REPEAT</li>
|
||||
<li>...</li>
|
||||
</ul>
|
||||
It can greatly improve readability.
|
||||
</div>
|
||||
|
||||
<h4>Example<u> - Use BOOST_PP_CAT instead of ## when necessary.</u></h4>
|
||||
<div class="code"><pre>
|
||||
#define STATIC_ASSERT(expr) \
|
||||
enum { BOOST_PP_CAT(static_check_, __LINE__) = (expr) ? 1 : -1 }; \
|
||||
typedef char \
|
||||
BOOST_PP_CAT(static_assert_, __LINE__)[BOOST_PP_CAT(static_check_, __LINE__)] \
|
||||
/**/
|
||||
|
||||
// ...
|
||||
|
||||
STATIC_ASSERT(sizeof(int) <= sizeof(long));
|
||||
</pre></div>
|
||||
<div>
|
||||
<b>Why:</b> Macro expansion proceeds recursively in "layers."
|
||||
Token pasting prevents the preprocessor from performing macro expansion,
|
||||
therefore it is often necessary to delay token concatenation.
|
||||
</div>
|
||||
|
||||
<h4>Example<u> - Use BOOST_PP_STRINGIZE instead of # whenever necessary.</u></h4>
|
||||
<div class="code"><pre>
|
||||
#define NOTE(str) \
|
||||
message(__FILE__ "(" BOOST_PP_STRINGIZE(__LINE__) ") : " str) \
|
||||
/**/
|
||||
|
||||
// ...
|
||||
|
||||
#pragma NOTE("TBD!")
|
||||
</pre></div>
|
||||
<div>
|
||||
<b>Why:</b> Macro expansion proceeds recursively in "layers."
|
||||
Stringization prevents the preprocessor from performing macro expansion, therefore it is often necessary to delay stringization.
|
||||
</div>
|
||||
|
||||
<h4>Example<u> - Use BOOST_PP_ENUM_PARAMS (and its variants) or BOOST_PP_REPEAT and BOOST_PP_COMMA_IF to avoid <i>O</i>(<i>n</i>) repetition on lists in general.</u></h4>
|
||||
<div class="code"><pre>
|
||||
struct make_type_list_end;
|
||||
|
||||
template<
|
||||
BOOST_PP_ENUM_PARAMS_WITH_A_DEFAULT(
|
||||
MAKE_TYPE_LIST_MAX_LENGTH,
|
||||
class T,
|
||||
make_type_list_end
|
||||
)
|
||||
>
|
||||
struct make_type_list {
|
||||
private:
|
||||
enum { end = is_same<T0, make_type_list_end>::value };
|
||||
public:
|
||||
typedef typename type_if<
|
||||
end, type_cons_empty,
|
||||
type_cons<
|
||||
T0,
|
||||
typename type_inner_if<
|
||||
end, type_identity<end>,
|
||||
make_type_list<
|
||||
BOOST_PP_ENUM_SHIFTED_PARAMS(
|
||||
MAKE_TYPE_LIST_MAX_LENGTH,
|
||||
T
|
||||
)
|
||||
>
|
||||
>::type
|
||||
>
|
||||
>::type type;
|
||||
};
|
||||
</pre></div>
|
||||
<div>
|
||||
<b>How:</b> BOOST_PP_REPEAT uses simulated recursion (pseudo code):
|
||||
</div>
|
||||
<div><pre>
|
||||
#define BOOST_PP_REPEAT(n, m, p) BOOST_PP_REPEAT ## n(m, p)
|
||||
|
||||
#define BOOST_PP_REPEAT0(m, p)
|
||||
#define BOOST_PP_REPEAT1(m, p) m(0, p)
|
||||
#define BOOST_PP_REPEAT2(m, p) m(0, p) m(1, p)
|
||||
#define BOOST_PP_REPEAT3(m, p) BOOST_PP_REPEAT2(m, p) m(2, p)
|
||||
#define BOOST_PP_REPEAT4(m, p) BOOST_PP_REPEAT3(m, p) m(3, p)
|
||||
// ...
|
||||
</pre></div>
|
||||
<div>
|
||||
<i>Note: This is no longer how BOOST_PP_REPEAT is implemented, so the code above is illustrative only! </i>
|
||||
</div>
|
||||
<div>
|
||||
BOOST_PP_ENUM_PARAMS and its variations use BOOST_PP_REPEAT.
|
||||
BOOST_PP_COMMA_IF(I) expands to a comma if I != 0.
|
||||
BOOST_PP_INC(I) essentially expands to "I+1," and BOOST_PP_DEC(I) essentially expands to "I-1.".
|
||||
</div>
|
||||
|
||||
<h4>Example<u> - Use a <i>conditional macro definition</i> to enable user configuration of code repetition based on need rather than some "reasonable" upper limit.</u></h4>
|
||||
<div class="code"><pre>
|
||||
#ifndef MAKE_TYPE_LIST_MAX_LENGTH
|
||||
#define MAKE_TYPE_LIST_MAX_LENGTH 8
|
||||
#endif
|
||||
</pre></div>
|
||||
<div>
|
||||
Now the user can configure the <code>make_type_list</code> primitive without modifying library code.
|
||||
</div>
|
||||
|
||||
<h4>Example<u> - Use BOOST_PP_REPEAT and a <i>token look-up function</i> to eliminate categorical repetition.</u></h4>
|
||||
<div class="code"><pre>
|
||||
// CAVEAT: My compiler is not standard on arithmetic types.
|
||||
#define ARITHMETIC_TYPE(I) ARITHMETIC_TYPE ## I
|
||||
|
||||
#define ARITHMETIC_TYPE0 bool
|
||||
#define ARITHMETIC_TYPE1 char
|
||||
#define ARITHMETIC_TYPE2 signed char
|
||||
#define ARITHMETIC_TYPE3 unsigned char
|
||||
#define ARITHMETIC_TYPE4 short
|
||||
#define ARITHMETIC_TYPE5 unsigned short
|
||||
#define ARITHMETIC_TYPE6 int
|
||||
#define ARITHMETIC_TYPE7 unsigned int
|
||||
#define ARITHMETIC_TYPE8 long
|
||||
#define ARITHMETIC_TYPE9 unsigned long
|
||||
#define ARITHMETIC_TYPE10 float
|
||||
#define ARITHMETIC_TYPE11 double
|
||||
#define ARITHMETIC_TYPE12 long double
|
||||
|
||||
#define ARITHMETIC_TYPE_CNT 13
|
||||
|
||||
// ...
|
||||
|
||||
#define BOOST_PP_DEF(z, I, _) /* ... */ \
|
||||
catch (ARITHMETIC_TYPE(I) t) { \
|
||||
report_typeid(t); \
|
||||
report_value(t); \
|
||||
} \
|
||||
/**/
|
||||
|
||||
BOOST_PP_REPEAT(ARITHMETIC_TYPE_CNT, BOOST_PP_DEF, _)
|
||||
|
||||
#undef BOOST_PP_DEF
|
||||
</pre></div>
|
||||
<div>
|
||||
<b>Note:</b> The repetition of the above example can be eliminated using template metaprogramming <a href="bibliography.html#czarnecki">[Czarnecki]</a> as well.
|
||||
However categorical repetition of operator tokens cannot be completely eliminated by using template metaprogramming.
|
||||
</div>
|
||||
|
||||
<h4>Example<u> - Use BOOST_PP_REPEAT to avoid <i>O</i>(<i>n</i>*<i>n</i>) repetition.</u></h4>
|
||||
<div class="code"><pre>
|
||||
#ifndef MAX_VEC_ARG_CNT
|
||||
#define MAX_VEC_ARG_CNT 8
|
||||
#endif
|
||||
|
||||
// ...
|
||||
|
||||
#define ARG_FUN(z, i, _) BOOST_PP_COMMA_IF(i) T a ## i
|
||||
#define ASSIGN_FUN(z, i, ) (*this)[i] = a ## i;
|
||||
|
||||
#define DEF_VEC_CTOR_FUN(z, i, _) /* ... */ \
|
||||
vec(BOOST_PP_REPEAT(i, ARG_FUN, _)) { \
|
||||
BOOST_PP_REPEAT(i, ASSIGN_FUN, _) \
|
||||
} \
|
||||
/**/
|
||||
|
||||
BOOST_PP_REPEAT(BOOST_PP_INC(MAX_VEC_ARG_CNT), DEF_VEC_CTOR_FUN, _)
|
||||
|
||||
#undef ARG_FUN
|
||||
#undef ASSIGN_FUN
|
||||
#undef DEF_VEC_CTOR_FUN
|
||||
|
||||
// ...
|
||||
</pre></div>
|
||||
<div>
|
||||
<b>How:</b> BOOST_PP_REPEAT is implemented is a special way to enable <i>automatic recursion</i>.
|
||||
</div>
|
||||
|
||||
<h4>Example<u> - Use BOOST_PP_IF to implement special case for the first element.</u></h4>
|
||||
<div class="code"><pre>
|
||||
#define COMMA_IF(c) \
|
||||
BOOST_PP_IF(c, BOOST_PP_COMMA, BOOST_PP_EMPTY)() \
|
||||
/**/
|
||||
|
||||
BOOST_PP_IF(0, true, false) == false;
|
||||
BOOST_PP_IF(1, true, false) == true;
|
||||
</pre></div>
|
||||
<div>
|
||||
BOOST_PP_IF enables convenient generation of lists using BOOST_PP_REPEAT.
|
||||
</div>
|
||||
<div>
|
||||
<b>Note:</b> <i>THEN</i> and <i>ELSE</i> don't have to be macros.
|
||||
However, if at least one of them is a function-like macro, and you want it be expanded conditionally,
|
||||
you have to make the other parameter a function-like macro too.
|
||||
This can often be done using BOOST_PP_IDENTITY.
|
||||
Consider the following example (by Aleksey Gurtovoy):
|
||||
</div>
|
||||
<div><pre>
|
||||
#define NUMBERED_EXPRESSION(i, x) /* ... */ \
|
||||
BOOST_PP_IF( \
|
||||
i, \
|
||||
BOOST_PP_IDENTITY(x ## i) \
|
||||
BOOST_PP_EMPTY \
|
||||
)() \
|
||||
/**/
|
||||
</pre></div>
|
||||
<div>
|
||||
<b>Note:</b> Like in the above implementation of COMMA_IF, the result of BOOST_PP_IF is often invoked and not the <i>THEN</i> and <i>ELSE</i> parameters.
|
||||
If the parameters were invoked, the code would not expand correctly, because the BOOST_PP_EMPTY parameter would get expanded
|
||||
to nothing before the <b>BOOST_PP_IF</b> would be properly expanded.
|
||||
</div>
|
||||
<div>
|
||||
<b>How:</b> BOOST_PP_IF is defined for the entire repeat range (psuedo code):
|
||||
</div>
|
||||
<div><pre>
|
||||
#define BOOST_PP_IF(c, THEN, ELSE) BOOST_PP_IF ## c(THEN, ELSE)
|
||||
|
||||
#define BOOST_PP_IF0(THEN, ELSE) ELSE
|
||||
#define BOOST_PP_IF1(THEN, ELSE) THEN
|
||||
#define BOOST_PP_IF1(THEN, ELSE) THEN
|
||||
// ...
|
||||
</pre></div>
|
||||
|
||||
<h4>Example:<u> Use arithmetic, logical, and comparison operations when necessary.</u></h4>
|
||||
<div class="code"><pre>
|
||||
#define SPECIAL_NUMBERED_LIST(n, i, elem, special) \
|
||||
BOOST_PP_ASSERT_MSG( \
|
||||
BOOST_PP_LESS(i, n), \
|
||||
bad params for SPECIAL_NUMBERED_LIST! \
|
||||
) \
|
||||
BOOST_PP_ENUM_PARAMS(i, elem) \
|
||||
BOOST_PP_COMMA_IF(i) special \
|
||||
BOOST_PP_REPEAT( \
|
||||
BOOST_PP_SUB(BOOST_PP_DEC(n), i), \
|
||||
SPECIAL_NUMBERED_LIST_HELPER, \
|
||||
(elem, i) \
|
||||
) \
|
||||
/**/
|
||||
|
||||
#define SPECIAL_NUMBERED_LIST_HELPER(z, i, elem_base) \
|
||||
, \
|
||||
BOOST_PP_CAT( \
|
||||
BOOST_PP_TUPLE_ELEM(2, 0, elem_base), \
|
||||
BOOST_PP_ADD( \
|
||||
i, \
|
||||
BOOST_PP_TUPLE_ELEM(2, 1, elem_base) \
|
||||
) \
|
||||
) \
|
||||
/**/
|
||||
|
||||
SPECIAL_NUMBERED_LIST(3, 0, E, S)
|
||||
SPECIAL_NUMBERED_LIST(3, 1, E, S)
|
||||
SPECIAL_NUMBERED_LIST(3, 2, E, S)
|
||||
SPECIAL_NUMBERED_LIST(3, 3, E, S)
|
||||
</pre></div>
|
||||
|
||||
<hr size="1">
|
||||
<div style="margin-left: 0px;">
|
||||
<i><EFBFBD> Copyright <a href="http://www.housemarque.com" target="_top">Housemarque Oy</a> 2002</i>
|
||||
</div>
|
||||
<div style="margin-left: 0px;">
|
||||
Permission to copy, use, modify, sell and distribute this document is granted provided this copyright notice appears in all copies.
|
||||
This document is provided "as is" without express or implied warranty and with no claim as to its suitability for any purpose.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
Reference in New Issue
Block a user