|
Boost : |
From: Stjepan Rajko (stipe_at_[hidden])
Date: 2007-05-30 19:16:10
Hello,
I would like to propose an extension to the Preprocessor library,
based on the REPEAT, ENUM etc. family of macros, e.g.,
BOOST_PP_REPEAT(count, macro, data) macro which expands to:
macro(z, 0, data) macro(z, 1, data) ... macro(z, count - 1, data)
In working on the RPC and Signal Network libraries, I found useful
being able to iterate over multiple macros simultaneously. This could
be provided by a set of macros BOOST_PP_REPEAT_(C|M|MA)+ where C
stands for Constant, M for Macro, and MA for Macro+Argument. For
example,
BOOST_PP_REPEAT_CMAMC(count, cons, macro, arg, macro2, cons2) expands
to (linebreaks inserted for readability):
cons macro(z, 0, arg) macro2(z, 0, BOOST_PP_EMPTY()) cons2
cons macro(z, 1, arg) macro2(z, 1, BOOST_PP_EMPTY()) cons2
...
cons macro(z, count-1, arg) macro2(z, count-1, BOOST_PP_EMPTY()) cons2
This particular macro would be implemented as
#define BOOST_PP_CMAMC_MACRO(z, n, args) \
BOOST_PP_TUPLE_ELEM(5, 0, args) \
BOOST_PP_TUPLE_ELEM(5, 1, args)(z,n,BOOST_PP_TUPLE_ELEM(5, 2, args)) \
BOOST_PP_TUPLE_ELEM(5, 3, args)(z,n,BOOST_PP_EMPTY()) \
BOOST_PP_TUPLE_ELEM(5, 4, args)
#define BOOST_PP_REPEAT_CMAMC(count, c1, m2, a3, m4, c5) \
BOOST_PP_REPEAT(count, BOOST_PP_CMAMC_MACRO, (c1, m2, a3, m4, c5))
As a usage example, I am finding such expansions useful in developing
classes / functions in which an integer template parameter determines
the number of arguments to a function/method and/or the number of
local/class variables (for example, when the function signature is
determined by a signature provided as a template parameter, and the
function needs a local variable for each parameter). In this case, I
iterate over the a template implementation using BOOST_PP_ITERATE and
have a set of macros equivalent to the ones above, except they
hard-code the count to BOOST_PP_ITERATION() (they are called
BOOST_ARITY_* instead of BOOST_PP_*).
Take as an example a function "serialize" which is templated on a
function Signature, where the arguments of the function are specified
by the signature. For example,
std::string serialized_params;
serialized_params = serialize<void(int, float, std::string)>(1, 2.5,
"serialize this");
The above macros make the following implementation a little more
readable than other alternatives I've come accross (what follows is
adapted from working code and untested):
--- first some prep work, so we have macros to iterate over:
// define names a1, a2, ...
#define ARITY_aN_NAME(z,n,data) \
BOOST_PP_CAT(a,BOOST_PP_INC(n))
// define names arg1_type, arg2_type, ...:
#define ARITY_argN_type_NAME(z,n,data) \
BOOST_PP_CAT(BOOST_PP_CAT(arg,BOOST_PP_INC(n)),_type)
// define a way to get to the type of an argument, given the signature:
#define ARITY_function_traits_argN_type_NAME(z,n,signature) \
typename boost::function_traits<signature>:: \
ARITY_argN_type_NAME(z,n,BOOST_PP_EMPTY())
// just some shortcuts:
#define BOOST_ARITY_ENUM_MAM(m1, a2, m3) \
BOOST_PP_ENUM_MAM(BOOST_PP_ITERATION(), m1, m2, m3)
#define BOOST_ARITY_REPEAT_CMC(c1, m2, c3) \
BOOST_PP_REPEAT_CMC(BOOST_PP_ITERATION(), c1, m2, c3)
---- the following part is iterated over using BOOST_PP_ITERATE:
// define a function which serializes its arguments, and the
// number and type of arguments is specified by a template param:
template<typename Signature>
// retuns a string
typename boost::enable_if_c<boost::function_traits<Signature>::arity
==BOOST_PP_ITERATION(), std::string>::type
// the list of arguments is expanded through the macros:
// (typename boost::function_traits<Signature>::arg1_type a1,
// typename boost::function_traits<Signature>::arg2_type a2, ...)
serialize(BOOST_ARITY_ENUM_MAM(ARITY_function_traits_argN_type_NAME,
Signature, ARITY_aN_NAME))
{
std::stringstream stream(std::ios::in | std::ios::out | std::ios::binary);
boost::archive::binary_oarchive archive(stream);
// archive & a1; archive & a2; ...
BOOST_ARITY_REPEAT_CMC(archive &, ARITY_aN_NAME, ;)
return stream.str();
}
--- The BOOST_ARITY_* macros above are easily implemented using BOOST_PP_* macros, and are just one usage example. Macros of the type BOOST_PP_REPEAT_(C|M|MA)+ could probably have other applications as well. If there isn't functionality which already covers this, would there be any interest in adding the BOOST_PP_REPEAT_(C|M|MA)+ etc. macros to the preprocessor library? If so, I could write up a python script which would generate the macros for up to a reasonable number of arguments (e.g., four C, M, or MAs which would lead to 3^4 base macros plus the same number of BOOST_PP_REPEAT_*, BOOST_PP_EVAL_*, and any other macros that should be included). Regards, Stjepan
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk