Boost logo

Boost Users :

From: Paul Mensonides (pmenso57_at_[hidden])
Date: 2006-06-14 22:58:07


 

> -----Original Message-----
> From: boost-users-bounces_at_[hidden]
> [mailto:boost-users-bounces_at_[hidden]] On Behalf Of Chris Weed
> Sent: Wednesday, June 14, 2006 6:24 PM
> To: boost-users_at_[hidden]
> Subject: Re: [Boost-users] [preprocessor] concatenating
> values tocreatetypedefpermutations
>
> Sorry for my poor explanation.
> What I was trying to do was permute the types that weren't
> MyClassA and MyClassB
>
> Such as:
> typedef MyClassA<float,MyClassB<bool,char>,int> My_fbci;
> typedef MyClassA<float,MyClassB<bool,char>,float> My_fbcf;
> typedef MyClassA<char,MyClassB<float,float>,float> My_cfff;
> typedef MyClassA<float,MyClassB<int,float>,float> My_fiff; ...

#define A(r, product) \
    typedef MyClass< \
        BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_TRANSFORM(B, 1, product)) \
> \
    BOOST_PP_SEQ_CAT((My) BOOST_PP_SEQ_TRANSFORM(B, 0, product)); \
    /**/
#define B(s, i, elem) BOOST_PP_SEQ_ELEM(i, elem)

Okay, in this part of the code, the 'product' argument that is passed to 'A' is
a sequence containing a particular permutation (e.g. (char)(int)). However,
because we're passing the single letters to use in the construction of the
typedef name, that sequence is actually, e.g., ((c)(char))((i)(int)). IOW, a
sequence where each element is another sequence that contains a letter and a
type. The SEQ_TRANSFORMs are just converting that sequence into (char)(int) and
(c)(i) respectively so that we can reuse other already-defined library
primitives like SEQ_ENUM and SEQ_CAT. Long story short, we have the permutation
in 'product', we just need to extract the parts that we need at various
locations:

#include <boost/preprocessor/seq/cat.hpp>
#include <boost/preprocessor/seq/elem.hpp>
#include <boost/preprocessor/seq/for_each_product.hpp>
#include <boost/preprocessor/seq/transform.hpp>

// Here we change A so that it just splits the
// permutation sequence into two sequences--
// one containing the types and one containing
// the letters--which we just forward to C.
// E.g.
//
// ((c)(char)) ((i)(int)) ((d)(double)) ((f)(float))
// -> (char)(int)(double)(float)
// -> (c)(i)(d)(f)
//
// The first transformation (the types) isn't
// strictly necessary, but it makes the syntax
// cleaner in C. Without that transformation,
// access to the n-th type in the permutation
// would be SEQ_ELEM(1, SEQ_ELEM(n, product)).
// Pulling the types out into a separate
// sequence results in SEQ_ELEM(n, types)
// instead. The second transformation is
// necessary if we want to use SEQ_CAT to make
// the typedef name.

#define A(r, product) \
    C( \
        BOOST_PP_SEQ_TRANSFORM(B, 1, product), \
        BOOST_PP_SEQ_TRANSFORM(B, 0, product) \
    ) \
    /**/
#define B(s, i, elem) BOOST_PP_SEQ_ELEM(i, elem)

// Here we just extract the types from the
// the 'types' sequence were we want them.
// The typedef name is constructed the same as
// before.

#define C(types, letters) \
    typedef MyClassA< \
        BOOST_PP_SEQ_ELEM(0, types), \
        MyClassB< \
            BOOST_PP_SEQ_ELEM(1, types), \
            BOOST_PP_SEQ_ELEM(2, types) \
>, \
        BOOST_PP_SEQ_ELEM(3, types) \
> BOOST_PP_SEQ_CAT((My_) letters); \
    /**/

#define TYPE(alpha, id) ((alpha)(id))

// The above mechanics require each permutation to
// contain four elements, so we need to have four
// input sequences. SEQ_FOR_EACH_PRODUCT will invoke
// A with all possible combinations containing one
// element from each input sequence.

BOOST_PP_SEQ_FOR_EACH_PRODUCT(
    A,
    ( TYPE(c, char) TYPE(i, int) TYPE(f, float) )
    ( TYPE(c, char) TYPE(i, int) TYPE(f, float) )
    ( TYPE(c, char) TYPE(i, int) TYPE(f, float) )
    ( TYPE(c, char) TYPE(i, int) TYPE(f, float) )
)

#undef A
#undef B
#undef C
#undef TYPE

A word of warning, however. What is being produced here is a combinatorial
explosion and the algorithm is exponential. Therefore, if your sequences of
types get longer and there are more of them, eventually the performance of the
preprocessor will be so slow as to make this method of generation unusable.

Regards,
Paul Mensonides


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net