241 lines
8.2 KiB
Plaintext
241 lines
8.2 KiB
Plaintext
[/
|
|
(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]
|