]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | [/ |
2 | (C) Copyright Edward Diener 2011-2015 | |
3 | Distributed under the Boost Software License, Version 1.0. | |
4 | (See accompanying file LICENSE_1_0.txt or copy at | |
5 | http://www.boost.org/LICENSE_1_0.txt). | |
6 | ] | |
7 | ||
8 | [section:vmd_identity Generating emptiness and identity] | |
9 | ||
10 | [heading Using BOOST_PP_EMPTY and BOOST_PP_IDENTITY] | |
11 | ||
12 | Boost PP Has a macro called BOOST_PP_EMPTY() which expands to nothing. | |
13 | ||
14 | Ordinarily this would not seem that useful, but the macro can be used | |
15 | in situations where one wants to return a specific value even though | |
16 | a further macro call syntax is required taking no parameters. | |
17 | This sort of usefulness occurs in Boost PP when there are two paths to take depending | |
18 | on the outcome of a BOOST_PP_IF or BOOST_PP_IIF logic. Here is an artificial example: | |
19 | ||
20 | #include <boost/preprocessor/control/iif.hpp> | |
21 | #include <boost/preprocessor/facilities/empty.hpp> | |
22 | ||
23 | #define MACRO_CHOICE(parameter) \ | |
24 | BOOST_PP_IIF(parameter) \ | |
25 | ( \ | |
26 | MACRO_CALL_IF_PARAMETER_1, \ | |
27 | SOME_FIXED_VALUE BOOST_PP_EMPTY \ | |
28 | ) \ | |
29 | () | |
30 | ||
31 | #define MACRO_CALL_IF_PARAMETER_1() some_processing | |
32 | ||
33 | In the general logic above is: if parameter is 1 another | |
34 | macro is invoked, whereas if the parameter is 0 some | |
35 | fixed value is returned. The reason that this is useful | |
36 | is that one may not want to code the MACRO_CHOICE macro | |
37 | in this way: | |
38 | ||
39 | #include <boost/preprocessor/control/iif.hpp> | |
40 | ||
41 | #define MACRO_CHOICE(parameter) \ | |
42 | BOOST_PP_IIF(parameter) \ | |
43 | ( \ | |
44 | MACRO_CALL_IF_PARAMETER_1(), \ | |
45 | SOME_FIXED_VALUE \ | |
46 | ) | |
47 | ||
48 | #define MACRO_CALL_IF_PARAMETER_1() some_processing | |
49 | ||
50 | because it is inefficient. The invocation of MACRO_CALL_IF_PARAMETER_1 will still | |
51 | be generated even when 'parameter' is 0. | |
52 | ||
53 | This idiom of returning a fixed value through the use of BOOST_PP_EMPTY | |
54 | is so useful that Boost PP has an accompanying macro to BOOST_PP_EMPTY to | |
55 | work with it. This accompanying macro is BOOST_PP_IDENTITY(value)(). | |
56 | Essentially BOOST_PP_IDENTITY returns its value when it is invoked. | |
57 | Again, like BOOST_PP_EMPTY, the final invocation must be done with no value. | |
58 | ||
59 | Our example from above, which originally used BOOST_PP_EMPTY to return | |
60 | a fixed value, is now: | |
61 | ||
62 | #include <boost/preprocessor/control/iif.hpp> | |
63 | #include <boost/preprocessor/facilities/identity.hpp> | |
64 | ||
65 | #define MACRO_CHOICE(parameter) \ | |
66 | BOOST_PP_IIF(parameter) \ | |
67 | ( \ | |
68 | MACRO_CALL_IF_PARAMETER_1, \ | |
69 | BOOST_PP_IDENTITY(SOME_FIXED_VALUE) \ | |
70 | ) \ | |
71 | () | |
72 | ||
73 | #define MACRO_CALL_IF_PARAMETER_1() some_processing | |
74 | ||
75 | The macro BOOST_PP_IDENTITY is actually just: | |
76 | ||
77 | #define BOOST_PP_IDENTITY(value) value BOOST_PP_EMPTY | |
78 | ||
79 | so you can see how it is essentially a shorthand for the common | |
80 | case originally shown at the top of returning a value through the | |
81 | use of BOOST_PP_EMPTY. | |
82 | ||
83 | [heading Using BOOST_VMD_EMPTY and BOOST_VMD_IDENTITY] | |
84 | ||
85 | The one problem when using BOOST_PP_EMPTY and BOOST_PP_IDENTITY | |
86 | is that the final invocation must be with no parameters. This is | |
87 | very limiting. If the final invocation must be with one or more parameters | |
88 | you cannot use BOOST_PP_EMPTY or BOOST_PP_IDENTITY. In other words, | |
89 | making a change to either of our two examples: | |
90 | ||
91 | #include <boost/preprocessor/control/iif.hpp> | |
92 | #include <boost/preprocessor/facilities/empty.hpp> | |
93 | ||
94 | #define MACRO_CHOICE(parameter1,parameter2) \ | |
95 | BOOST_PP_IIF(parameter1) \ | |
96 | ( \ | |
97 | MACRO_CALL_IF_PARAMETER_1, \ | |
98 | SOME_FIXED_VALUE BOOST_PP_EMPTY \ | |
99 | ) \ | |
100 | (parameter2) | |
101 | ||
102 | #define MACRO_CALL_IF_PARAMETER_1(parameter2) some_processing_using_a_parameter | |
103 | ||
104 | or | |
105 | ||
106 | #include <boost/preprocessor/control/iif.hpp> | |
107 | #include <boost/preprocessor/facilities/identity.hpp> | |
108 | ||
109 | #define MACRO_CHOICE(parameter1,parameter2) \ | |
110 | BOOST_PP_IIF(parameter1) \ | |
111 | ( \ | |
112 | MACRO_CALL_IF_PARAMETER_1, \ | |
113 | BOOST_PP_IDENTITY(SOME_FIXED_VALUE) \ | |
114 | ) \ | |
115 | (parameter2) | |
116 | ||
117 | #define MACRO_CALL_IF_PARAMETER_1(parameter2) some_processing_using_a_parameter | |
118 | ||
119 | will produce a preprocessing error since the final invocation to either | |
120 | BOOST_PP_EMPTY or BOOST_PP_IDENTITY can not be done with 1 or more parameters. | |
121 | ||
122 | It would be much more useful if the final invocation could be done with | |
123 | any number of parameters. This is where using variadic macros solves the problem. | |
124 | The BOOST_VMD_EMPTY and BOOST_VMD_IDENTITY macros have the exact same | |
125 | functionality as their Boost PP counterparts but the final invocation can | |
126 | be made with any number of parameters, and those parameters are just ignored | |
127 | when BOOST_VMD_EMPTY or BOOST_VMD_IDENTITY is the choice. | |
128 | ||
129 | Now for our two examples we can have: | |
130 | ||
131 | #include <boost/preprocessor/control/iif.hpp> | |
132 | #include <boost/vmd/empty.hpp> | |
133 | ||
134 | #define MACRO_CHOICE(parameter1,parameter2) \ | |
135 | BOOST_PP_IIF(parameter1) \ | |
136 | ( \ | |
137 | MACRO_CALL_IF_PARAMETER_1, \ | |
138 | SOME_FIXED_VALUE BOOST_VMD_EMPTY \ | |
139 | ) \ | |
140 | (parameter2) | |
141 | ||
142 | #define MACRO_CALL_IF_PARAMETER_1(parameter2) some_processing_using_parameters | |
143 | ||
144 | or | |
145 | ||
146 | #include <boost/preprocessor/control/iif.hpp> | |
147 | #include <boost/vmd/identity.hpp> | |
148 | ||
149 | #define MACRO_CHOICE(parameter1,parameter2) \ | |
150 | BOOST_PP_IIF(parameter1) \ | |
151 | ( \ | |
152 | MACRO_CALL_IF_PARAMETER_1, \ | |
153 | BOOST_VMD_IDENTITY(SOME_FIXED_VALUE) \ | |
154 | ) \ | |
155 | (parameter2) | |
156 | ||
157 | #define MACRO_CALL_IF_PARAMETER_1(parameter2) some_processing_using_parameters | |
158 | ||
159 | and our macros will compile without preprocessing errors and work as expected. | |
160 | Both BOOST_VMD_EMPTY and BOOST_VMD_IDENTITY will take any number of parameters | |
161 | in their invocation, which makes them useful for a final invocation no matter | |
162 | what is being passed. | |
163 | ||
164 | [heading Usage for BOOST_VMD_EMPTY and BOOST_VMD_IDENTITY] | |
165 | ||
166 | To use the BOOST_VMD_EMPTY macro either include the general header: | |
167 | ||
168 | #include <boost/vmd/vmd.hpp> | |
169 | ||
170 | or include the specific header: | |
171 | ||
172 | #include <boost/vmd/empty.hpp> | |
173 | ||
174 | To use the BOOST_VMD_IDENTITY macro either include the general header: | |
175 | ||
176 | #include <boost/vmd/vmd.hpp> | |
177 | ||
178 | or include the specific header: | |
179 | ||
180 | #include <boost/vmd/identity.hpp> | |
181 | ||
182 | [heading Using BOOST_VMD_EMPTY and BOOST_VMD_IDENTITY with VC++] | |
183 | ||
184 | Unfortunately the Visual C++ preprocessor has a problem when a macro | |
185 | expands to something followed by a variadic macro which expands to nothing. | |
186 | This is the case when using BOOST_VMD_EMPTY following some non-empty expansion, | |
187 | or the equivalent use of BOOST_VMD_IDENTITY. As strange as it sounds this VC++ | |
188 | preprocessor problem is normally solved by concatenating the result using BOOST_PP_CAT | |
189 | with an empty value. But then again the many non-standard behaviors of VC++ | |
190 | are difficult to understand or even track. | |
191 | ||
192 | In order to make this technique transparent when used with a C++ standard | |
193 | conforming preprocessor or VC++ non-standard preprocessor you can use the | |
194 | BOOST_VMD_IDENTITY_RESULT macro passing to it a single parameter which is a result | |
195 | returned from a macro which uses BOOST_VMD_IDENTITY ( or its equivalent | |
196 | 'value BOOST_VMD_EMPTY' usage ). | |
197 | ||
198 | Given our MACRO_CHOICE example above, if you have another macro invoking MACRO_CHOICE | |
199 | simply enclose that invocation within BOOST_VMD_IDENTITY_RESULT. As in the very simple: | |
200 | ||
201 | #include <boost/vmd/identity.hpp> | |
202 | ||
203 | #define CALLING_MACRO_CHOICE(parameter1,parameter2) \ | |
204 | BOOST_VMD_IDENTITY_RESULT(MACRO_CHOICE(parameter1,parameter2)) | |
205 | ||
206 | Alternatively you can change MACRO_CHOICE so that its implementation | |
207 | and usage is: | |
208 | ||
209 | #include <boost/preprocessor/control/iif.hpp> | |
210 | #include <boost/vmd/identity.hpp> | |
211 | ||
212 | #define MACRO_CHOICE(parameter1,parameter2) \ | |
213 | BOOST_VMD_IDENTITY_RESULT \ | |
214 | ( \ | |
215 | BOOST_PP_IIF(parameter1) \ | |
216 | ( \ | |
217 | MACRO_CALL_IF_PARAMETER_1, \ | |
218 | BOOST_VMD_IDENTITY(SOME_FIXED_VALUE) \ | |
219 | ) \ | |
220 | (parameter2) \ | |
221 | ) | |
222 | ||
223 | #define CALLING_MACRO_CHOICE(parameter1,parameter2) \ | |
224 | MACRO_CHOICE(parameter1,parameter2) | |
225 | ||
226 | Using BOOST_VMD_EMPTY and BOOST_VMD_IDENTITY in this way will ensure they can be used | |
227 | without preprocessing problems with either VC++ or any C++ standard conforming preprocessor. | |
228 | ||
229 | [heading Usage for BOOST_VMD_IDENTITY_RESULT] | |
230 | ||
231 | The macro BOOST_VMD_IDENTITY_RESULT is in the same header file as BOOST_VMD_IDENTITY, | |
232 | so to use the BOOST_VMD_IDENTITY_RESULT macro either include the general header: | |
233 | ||
234 | #include <boost/vmd/vmd.hpp> | |
235 | ||
236 | or include the specific header: | |
237 | ||
238 | #include <boost/vmd/identity.hpp> | |
239 | ||
240 | [endsect] |