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 12Boost PP Has a macro called BOOST_PP_EMPTY() which expands to nothing. 13 14Ordinarily this would not seem that useful, but the macro can be used 15in situations where one wants to return a specific value even though 16a further macro call syntax is required taking no parameters. 17This sort of usefulness occurs in Boost PP when there are two paths to take depending 18on 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 33In the general logic above is: if parameter is 1 another 34macro is invoked, whereas if the parameter is 0 some 35fixed value is returned. The reason that this is useful 36is that one may not want to code the MACRO_CHOICE macro 37in 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 50because it is inefficient. The invocation of MACRO_CALL_IF_PARAMETER_1 will still 51be generated even when 'parameter' is 0. 52 53This idiom of returning a fixed value through the use of BOOST_PP_EMPTY 54is so useful that Boost PP has an accompanying macro to BOOST_PP_EMPTY to 55work with it. This accompanying macro is BOOST_PP_IDENTITY(value)(). 56Essentially BOOST_PP_IDENTITY returns its value when it is invoked. 57Again, like BOOST_PP_EMPTY, the final invocation must be done with no value. 58 59Our example from above, which originally used BOOST_PP_EMPTY to return 60a 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 75The macro BOOST_PP_IDENTITY is actually just: 76 77 #define BOOST_PP_IDENTITY(value) value BOOST_PP_EMPTY 78 79so you can see how it is essentially a shorthand for the common 80case originally shown at the top of returning a value through the 81use of BOOST_PP_EMPTY. 82 83[heading Using BOOST_VMD_EMPTY and BOOST_VMD_IDENTITY] 84 85The one problem when using BOOST_PP_EMPTY and BOOST_PP_IDENTITY 86is that the final invocation must be with no parameters. This is 87very limiting. If the final invocation must be with one or more parameters 88you cannot use BOOST_PP_EMPTY or BOOST_PP_IDENTITY. In other words, 89making 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 104or 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 119will produce a preprocessing error since the final invocation to either 120BOOST_PP_EMPTY or BOOST_PP_IDENTITY can not be done with 1 or more parameters. 121 122It would be much more useful if the final invocation could be done with 123any number of parameters. This is where using variadic macros solves the problem. 124The BOOST_VMD_EMPTY and BOOST_VMD_IDENTITY macros have the exact same 125functionality as their Boost PP counterparts but the final invocation can 126be made with any number of parameters, and those parameters are just ignored 127when BOOST_VMD_EMPTY or BOOST_VMD_IDENTITY is the choice. 128 129Now 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 144or 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 159and our macros will compile without preprocessing errors and work as expected. 160Both BOOST_VMD_EMPTY and BOOST_VMD_IDENTITY will take any number of parameters 161in their invocation, which makes them useful for a final invocation no matter 162what is being passed. 163 164[heading Usage for BOOST_VMD_EMPTY and BOOST_VMD_IDENTITY] 165 166To use the BOOST_VMD_EMPTY macro either include the general header: 167 168 #include <boost/vmd/vmd.hpp> 169 170or include the specific header: 171 172 #include <boost/vmd/empty.hpp> 173 174To use the BOOST_VMD_IDENTITY macro either include the general header: 175 176 #include <boost/vmd/vmd.hpp> 177 178or 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 184Unfortunately the Visual C++ preprocessor has a problem when a macro 185expands to something followed by a variadic macro which expands to nothing. 186This is the case when using BOOST_VMD_EMPTY following some non-empty expansion, 187or the equivalent use of BOOST_VMD_IDENTITY. As strange as it sounds this VC++ 188preprocessor problem is normally solved by concatenating the result using BOOST_PP_CAT 189with an empty value. But then again the many non-standard behaviors of VC++ 190are difficult to understand or even track. 191 192In order to make this technique transparent when used with a C++ standard 193conforming preprocessor or VC++ non-standard preprocessor you can use the 194BOOST_VMD_IDENTITY_RESULT macro passing to it a single parameter which is a result 195returned from a macro which uses BOOST_VMD_IDENTITY ( or its equivalent 196'value BOOST_VMD_EMPTY' usage ). 197 198Given our MACRO_CHOICE example above, if you have another macro invoking MACRO_CHOICE 199simply 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 206Alternatively you can change MACRO_CHOICE so that its implementation 207and 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 226Using BOOST_VMD_EMPTY and BOOST_VMD_IDENTITY in this way will ensure they can be used 227without preprocessing problems with either VC++ or any C++ standard conforming preprocessor. 228 229[heading Usage for BOOST_VMD_IDENTITY_RESULT] 230 231The macro BOOST_VMD_IDENTITY_RESULT is in the same header file as BOOST_VMD_IDENTITY, 232so to use the BOOST_VMD_IDENTITY_RESULT macro either include the general header: 233 234 #include <boost/vmd/vmd.hpp> 235 236or include the specific header: 237 238 #include <boost/vmd/identity.hpp> 239 240[endsect] 241