Evaluated Slots
Evaluated slots is a mechanism to fully evaluate a constant expression
to avoid the normal lazy evaluation of the preprocessor.
Tutorial
In order to understand the use of such a mechanism, we will start with a
simple file iteration example. Consider the following scenario....
for (int i = 0; i < 10; ++i) {
for (int j = 0; j < i; ++j) {
// ... use i and j
}
}
This is a simple model of the following multiple-depth file iteration....
#if !defined(BOOST_PP_IS_ITERATING)
#ifndef FILE_HPP
#define FILE_HPP
#include <boost/preprocessor/iterate.hpp>
#define BOOST_PP_ITERATION_PARAMS_1 (0, 9, "file.hpp")
??=include BOOST_PP_ITERATE()
#endif
#elif BOOST_PP_ITERATION_DEPTH() == 1
#define I BOOST_PP_ITERATION()
#define BOOST_PP_ITERATION_PARAMS_2 (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
There is a big problem with the code above. The user expected I to refer
to the previous iteration frame. However, that is not the case.
When the user refers to I, he actually is referring to BOOST_PP_ITERATION().
This is exactly the same value to which J refers.
The problem is that the preprocessor always evaluates everything with lazy evaluation.
To solve the problem, we need I to be evaluated here:
// ...
#elif BOOST_PP_ITERATION_DEPTH() == 1
#define I BOOST_PP_ITERATION()
// ...
The library offers a mechanism to do just that: evaluated slots.
The following example uses this mechanism to "fix" the example above....
// ...
#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)
// ...
There are two steps to the assignment of an evaluated slot.
First, the user must define the macro BOOST_PP_VALUE. This value must be an
integral constant expression. Second, the user must include
BOOST_PP_ASSIGN_SLOT(x), where x is
a value between 1 and BOOST_PP_SLOT_LIMIT.  This will evaluate BOOST_PP_VALUE
and assign the result to the slot at index x.
To retrieve a slot's value, the user must use BOOST_PP_SLOT(x).
In the case above, I is still lazily evaluated. However, it now evaluates
to BOOST_PP_SLOT(1). This value will not change unless there is a subsequent
call to BOOST_PP_ASSIGN_SLOT(1).
Advanced...
The slot mechanism can also be used to perform calculations:
#include <iostream>
#include <boost/preprocessor/stringize.hpp>
#define X() 4
#define BOOST_PP_VALUE 1 + 2 + 3 + X()
??=include BOOST_PP_ASSIGN_SLOT(1)
int main(void) {
std::cout
<< BOOST_PP_STRINGIZE(BOOST_PP_SLOT(1))
<< &std::endl;
return 0;
}
In essence, anything that can be evaluated in an #if (or #elif) preprocessor directive
is available.
Some implementations will allow you to use the defined unary
operator in this context and others will not, so don't use defined if you want
the code to be fully portable. For example:
#define X
#define BOOST_PP_VALUE defined(X)
??=include BOOST_PP_ASSIGN_SLOT(1)
BOOST_PP_SLOT(1)
See Also