123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240 |
- [/
- (C) Copyright Edward Diener 2011-2015
- Distributed under the Boost Software License, Version 1.0.
- (See accompanying file LICENSE_1_0.txt or copy at
- http://www.boost.org/LICENSE_1_0.txt).
- ]
- [section:vmd_identity Generating emptiness and identity]
- [heading Using BOOST_PP_EMPTY and BOOST_PP_IDENTITY]
- Boost PP Has a macro called BOOST_PP_EMPTY() which expands to nothing.
- Ordinarily this would not seem that useful, but the macro can be used
- in situations where one wants to return a specific value even though
- a further macro call syntax is required taking no parameters.
- This sort of usefulness occurs in Boost PP when there are two paths to take depending
- on the outcome of a BOOST_PP_IF or BOOST_PP_IIF logic. Here is an artificial example:
- #include <boost/preprocessor/control/iif.hpp>
- #include <boost/preprocessor/facilities/empty.hpp>
- #define MACRO_CHOICE(parameter) \
- BOOST_PP_IIF(parameter) \
- ( \
- MACRO_CALL_IF_PARAMETER_1, \
- SOME_FIXED_VALUE BOOST_PP_EMPTY \
- ) \
- ()
-
- #define MACRO_CALL_IF_PARAMETER_1() some_processing
-
- In the general logic above is: if parameter is 1 another
- macro is invoked, whereas if the parameter is 0 some
- fixed value is returned. The reason that this is useful
- is that one may not want to code the MACRO_CHOICE macro
- in this way:
- #include <boost/preprocessor/control/iif.hpp>
- #define MACRO_CHOICE(parameter) \
- BOOST_PP_IIF(parameter) \
- ( \
- MACRO_CALL_IF_PARAMETER_1(), \
- SOME_FIXED_VALUE \
- )
-
- #define MACRO_CALL_IF_PARAMETER_1() some_processing
-
- because it is inefficient. The invocation of MACRO_CALL_IF_PARAMETER_1 will still
- be generated even when 'parameter' is 0.
- This idiom of returning a fixed value through the use of BOOST_PP_EMPTY
- is so useful that Boost PP has an accompanying macro to BOOST_PP_EMPTY to
- work with it. This accompanying macro is BOOST_PP_IDENTITY(value)().
- Essentially BOOST_PP_IDENTITY returns its value when it is invoked.
- Again, like BOOST_PP_EMPTY, the final invocation must be done with no value.
- Our example from above, which originally used BOOST_PP_EMPTY to return
- a fixed value, is now:
-
- #include <boost/preprocessor/control/iif.hpp>
- #include <boost/preprocessor/facilities/identity.hpp>
- #define MACRO_CHOICE(parameter) \
- BOOST_PP_IIF(parameter) \
- ( \
- MACRO_CALL_IF_PARAMETER_1, \
- BOOST_PP_IDENTITY(SOME_FIXED_VALUE) \
- ) \
- ()
-
- #define MACRO_CALL_IF_PARAMETER_1() some_processing
-
- The macro BOOST_PP_IDENTITY is actually just:
- #define BOOST_PP_IDENTITY(value) value BOOST_PP_EMPTY
-
- so you can see how it is essentially a shorthand for the common
- case originally shown at the top of returning a value through the
- use of BOOST_PP_EMPTY.
-
- [heading Using BOOST_VMD_EMPTY and BOOST_VMD_IDENTITY]
- The one problem when using BOOST_PP_EMPTY and BOOST_PP_IDENTITY
- is that the final invocation must be with no parameters. This is
- very limiting. If the final invocation must be with one or more parameters
- you cannot use BOOST_PP_EMPTY or BOOST_PP_IDENTITY. In other words,
- making a change to either of our two examples:
- #include <boost/preprocessor/control/iif.hpp>
- #include <boost/preprocessor/facilities/empty.hpp>
- #define MACRO_CHOICE(parameter1,parameter2) \
- BOOST_PP_IIF(parameter1) \
- ( \
- MACRO_CALL_IF_PARAMETER_1, \
- SOME_FIXED_VALUE BOOST_PP_EMPTY \
- ) \
- (parameter2)
-
- #define MACRO_CALL_IF_PARAMETER_1(parameter2) some_processing_using_a_parameter
-
- or
- #include <boost/preprocessor/control/iif.hpp>
- #include <boost/preprocessor/facilities/identity.hpp>
- #define MACRO_CHOICE(parameter1,parameter2) \
- BOOST_PP_IIF(parameter1) \
- ( \
- MACRO_CALL_IF_PARAMETER_1, \
- BOOST_PP_IDENTITY(SOME_FIXED_VALUE) \
- ) \
- (parameter2)
-
- #define MACRO_CALL_IF_PARAMETER_1(parameter2) some_processing_using_a_parameter
-
- will produce a preprocessing error since the final invocation to either
- BOOST_PP_EMPTY or BOOST_PP_IDENTITY can not be done with 1 or more parameters.
- It would be much more useful if the final invocation could be done with
- any number of parameters. This is where using variadic macros solves the problem.
- The BOOST_VMD_EMPTY and BOOST_VMD_IDENTITY macros have the exact same
- functionality as their Boost PP counterparts but the final invocation can
- be made with any number of parameters, and those parameters are just ignored
- when BOOST_VMD_EMPTY or BOOST_VMD_IDENTITY is the choice.
- Now for our two examples we can have:
- #include <boost/preprocessor/control/iif.hpp>
- #include <boost/vmd/empty.hpp>
- #define MACRO_CHOICE(parameter1,parameter2) \
- BOOST_PP_IIF(parameter1) \
- ( \
- MACRO_CALL_IF_PARAMETER_1, \
- SOME_FIXED_VALUE BOOST_VMD_EMPTY \
- ) \
- (parameter2)
-
- #define MACRO_CALL_IF_PARAMETER_1(parameter2) some_processing_using_parameters
-
- or
- #include <boost/preprocessor/control/iif.hpp>
- #include <boost/vmd/identity.hpp>
- #define MACRO_CHOICE(parameter1,parameter2) \
- BOOST_PP_IIF(parameter1) \
- ( \
- MACRO_CALL_IF_PARAMETER_1, \
- BOOST_VMD_IDENTITY(SOME_FIXED_VALUE) \
- ) \
- (parameter2)
-
- #define MACRO_CALL_IF_PARAMETER_1(parameter2) some_processing_using_parameters
-
- and our macros will compile without preprocessing errors and work as expected.
- Both BOOST_VMD_EMPTY and BOOST_VMD_IDENTITY will take any number of parameters
- in their invocation, which makes them useful for a final invocation no matter
- what is being passed.
- [heading Usage for BOOST_VMD_EMPTY and BOOST_VMD_IDENTITY]
- To use the BOOST_VMD_EMPTY macro either include the general header:
- #include <boost/vmd/vmd.hpp>
-
- or include the specific header:
- #include <boost/vmd/empty.hpp>
- To use the BOOST_VMD_IDENTITY macro either include the general header:
- #include <boost/vmd/vmd.hpp>
-
- or include the specific header:
- #include <boost/vmd/identity.hpp>
- [heading Using BOOST_VMD_EMPTY and BOOST_VMD_IDENTITY with VC++]
- Unfortunately the Visual C++ preprocessor has a problem when a macro
- expands to something followed by a variadic macro which expands to nothing.
- This is the case when using BOOST_VMD_EMPTY following some non-empty expansion,
- or the equivalent use of BOOST_VMD_IDENTITY. As strange as it sounds this VC++
- preprocessor problem is normally solved by concatenating the result using BOOST_PP_CAT
- with an empty value. But then again the many non-standard behaviors of VC++
- are difficult to understand or even track.
- In order to make this technique transparent when used with a C++ standard
- conforming preprocessor or VC++ non-standard preprocessor you can use the
- BOOST_VMD_IDENTITY_RESULT macro passing to it a single parameter which is a result
- returned from a macro which uses BOOST_VMD_IDENTITY ( or its equivalent
- 'value BOOST_VMD_EMPTY' usage ).
- Given our MACRO_CHOICE example above, if you have another macro invoking MACRO_CHOICE
- simply enclose that invocation within BOOST_VMD_IDENTITY_RESULT. As in the very simple:
- #include <boost/vmd/identity.hpp>
-
- #define CALLING_MACRO_CHOICE(parameter1,parameter2) \
- BOOST_VMD_IDENTITY_RESULT(MACRO_CHOICE(parameter1,parameter2))
-
- Alternatively you can change MACRO_CHOICE so that its implementation
- and usage is:
-
- #include <boost/preprocessor/control/iif.hpp>
- #include <boost/vmd/identity.hpp>
- #define MACRO_CHOICE(parameter1,parameter2) \
- BOOST_VMD_IDENTITY_RESULT \
- ( \
- BOOST_PP_IIF(parameter1) \
- ( \
- MACRO_CALL_IF_PARAMETER_1, \
- BOOST_VMD_IDENTITY(SOME_FIXED_VALUE) \
- ) \
- (parameter2) \
- )
-
- #define CALLING_MACRO_CHOICE(parameter1,parameter2) \
- MACRO_CHOICE(parameter1,parameter2)
-
- Using BOOST_VMD_EMPTY and BOOST_VMD_IDENTITY in this way will ensure they can be used
- without preprocessing problems with either VC++ or any C++ standard conforming preprocessor.
- [heading Usage for BOOST_VMD_IDENTITY_RESULT]
- The macro BOOST_VMD_IDENTITY_RESULT is in the same header file as BOOST_VMD_IDENTITY,
- so to use the BOOST_VMD_IDENTITY_RESULT macro either include the general header:
- #include <boost/vmd/vmd.hpp>
-
- or include the specific header:
- #include <boost/vmd/identity.hpp>
- [endsect]
|