1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 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>
|