Boost logo

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