|
Boost : |
From: Vesa Karvonen (vesa_karvonen_at_[hidden])
Date: 2003-01-05 11:25:35
Hi,
A typical use of the C preprocessor is to use object-like macros as flags
for controlling code expansion:
#if defined(OBJECT_LIKE_MACRO)
EXPANDED_IF_DEFINED
#else
EXPANDED_IF_NOT_DEFINED
#endif
The OBJECT_LIKE_MACRO is usually defined either in some configuration
header, or it may be defined on the command line. Most definitions are
either empty:
#define OBJECT_LIKE_MACRO
or expand to 1:
#define OBJECT_LIKE_MACRO 1
The above technique has a couple of problems. First of all, it can be
difficult to read, because preprocessor directives look very different from
ordinary C/C++ code. Furthermore, similar, but not exactly same, conditional
blocks (the above example is simplistic) may need to be used in several
places and it is quite tedious and verbose to make and use a parameterized
usable conditional block using the above base technique.
Preprocessor macros make parameterization and use easier. Unfortunately
there is no direct way to test, in a macro, whether some arbitrary macro is
defined. Usually the following tedious and verbose technique is used
instead:
#if defined(OBJECT_LIKE_MACRO)
# define OBJECT_LIKE_MACRO_BOOL 1
#else
# define OBJECT_LIKE_MACRO_BOOL 0
#endif
// ...
BOOST_PP_IF(OBJECT_LIKE_MACRO_BOOL,
EXPANDED_IF_DEFINED,
EXPANDED_IF_NOT_DEFINED)
Ideally, we would have a predicate "is_defined(NAME)" that could be used in
a macro:
BOOST_PP_IF(is_defined(OBJECT_LIKE_MACRO),
EXPANDED_IF_DEFINED,
EXPANDED_IF_NOT_DEFINED)
Unfortunately, it seems impossible to implement is_defined() using only
macros in the general case. In particular, consider the following macro
definition:
#define X X
Fortunately we do not necessarily need a complete is_defined() predicate. In
most cases we only have to detect if a NAME becomes empty or the token 1
when expanded. It seems possible to say the following:
BOOST_PP_IF(BOOST_PP_IS_EMPTY_OR_1(OBJECT_LIKE_MACRO),
EXPANDED_IF_DEFINED,
EXPANDED_IF_NOT_DEFINED)
I'd like to propose adding suitable predicate macros, in particular
BOOST_PP_IS_EMPTY(X), BOOST_PP_IS_1(X), BOOST_PP_IS_EMPTY_OR_1(X), to the
Boost Preprocessor library to help detect whether flag like macros are
defined. These macros would make it easier to move some logic from unusable
#if blocks into usable macros.
Best regards,
Vesa Karvonen
...
// The following has been tested only on GNU cpp.
#include "boost/preprocessor/cat.hpp"
#include "boost/preprocessor/control/iif.hpp"
#include "boost/preprocessor/logical/bitor.hpp"
#include "boost/preprocessor/tuple/elem.hpp"
// `x' shall either expand to become empty or expand to a part of
// identifier or numeric literal token.
#define BOOST_PP_IS_EMPTY(x)\
BOOST_PP_IS_EMPTY_DO(x BOOST_PP_IS_EMPTY_HELPER)
#define BOOST_PP_IS_EMPTY_DO(tuple_contents)\
BOOST_PP_TUPLE_ELEM(2,1,(BOOST_PP_##tuple_contents))
#define BOOST_PP_BOOST_PP_IS_EMPTY_HELPER 1, 1
#define BOOST_PP_IS_EMPTY_HELPER , 0
// `x' shall expand to a part of identifier or numeric literal token.
#define BOOST_PP_IS_1(x)\
BOOST_PP_IS_EMPTY(BOOST_PP_CAT(BOOST_PP_IS_1_HELPER_,x))
#define BOOST_PP_IS_1_HELPER_1
// `x' shall either expand to become empty or expand to a part of
// identifier or numeric literal token.
#define BOOST_PP_IS_EMPTY_OR_1(x)\
BOOST_PP_IIF(BOOST_PP_IS_EMPTY_DO(x BOOST_PP_IS_EMPTY_HELPER),\
1 BOOST_PP_EMPTY,\
BOOST_PP_IS_1)(x)
// The following is test code
#include "boost/preprocessor/facilities/empty.hpp"
#define EMPTY
0 : BOOST_PP_IS_EMPTY(__cplusplus)
1 : BOOST_PP_IS_1(__cplusplus)
0 : BOOST_PP_IS_EMPTY(NOT_EMPTY)
0 : BOOST_PP_IS_1(NOT_EMPTY)
1 : BOOST_PP_IS_EMPTY(EMPTY)
0 : BOOST_PP_IS_EMPTY(whatever)
1 : BOOST_PP_IS_EMPTY(BOOST_PP_EMPTY())
1 : BOOST_PP_IS_EMPTY_OR_1(BOOST_PP_EMPTY())
1 : BOOST_PP_IS_EMPTY_OR_1(1)
0 : BOOST_PP_IS_EMPTY_OR_1(A)
_________________________________________________________________
Add photos to your e-mail with MSN 8. Get 2 months FREE*.
http://join.msn.com/?page=features/featuredemail
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk