Boost logo

Boost :

From: Aleksey Gurtovoy (agurtovoy_at_[hidden])
Date: 2003-11-01 04:24:01


Sebastian Faust wrote:
> Hi,

Hi Sebastian,

> I wanna develope an factory class template which takes as template
argument
> a typelist and creates me then iterative objects of the types in the
> typelist. The different objects will be connected ( like in the chain of
> responsibility pattern ), so that after the creation process I only will
get
> back one pointer to the beginning object of the chain.
> I read about the boost::mpl -library and was very impressed, sadly I am
> absolutly new to metaprogramming so I really have some problems to solve
my
> problem, so I really would be thankful for any help.
>
> To show my problem I give a standard example about what I wanna do:
>
> class vehicle
> {
> public:
> vehicle(vehicle* successor) : m_successor(successor) {}
> virtual vehicle* create(vehicle* successor) = 0;
> vehicle* m_successor;
>
> };
> class car : public vehicle
> {
> public:
> car(car* successor) : vehicle(successor) {}
              ^^^^

I assume here and in other constructors below you meant 'vehicle*'.

> virtual vehicle* create(vehicle* successor)
> {
> return new car(successor);
> }
> };
>
> class bicycle : public vehicle
> {
> public:
> bicycle (bicycle * successor) : vehicle(successor) {}
> virtual vehicle* create(vehicle* successor)
> {
> return new bicycle (successor);
> }
> };
>
> class train : public vehicle
> {
> public:
> train (train * successor) : vehicle(successor) {}
> virtual vehicle* create(vehicle* successor)
> {
> return new train (successor);
> }
> };
>
> With the help of some from the ACCU mailinglist I could find out to use
the
> for_each template to iterate over a boost::mpl::list, but how can I get
the
> returned value from the method create?

So, IIUYC, you want to generate something along the following lines:

    vehicle* make(vehicle* v0)
    {
        vehicle* v1 = new car( v0 );
        vehicle* v2 = new bicycle( v1 );
        vehicle* v3 = new train( v2 );
        return v3;
    }

?

The simplest way would be something like this:

    namespace mpl = boost::mpl;
    using namespace mpl::placeholders;

    struct pass_through_make
    {
        static vehicle* make( vehicle* ptr )
        {
            return ptr;
        }
    };

    template< typename T, typename Base > struct make_vehicle
    {
        static vehicle* make( vehicle* ptr )
        {
            return new T( Base::make( ptr ) );
        }
    };

    typedef mpl::fold<
          mpl::vector<car,bicycle,train>
        , pass_through_make
        , make_vehicle<_2,_1>
>::type factory;

    int main()
    {
        factory::make( 0 );
        return 0;
    }

Basically, the above is equivalent to

    typedef make_vehicle<train
            , make_vehicle<bicycle
            , make_vehicle<car
            , pass_through_make
> > > factory;

    int main()
    {
        factory::make( 0 );
        return 0;
    }

See the docs for 'fold' (http://tinyurl.com/t8f5) for more information.

<digression>
Of course ideally Fusion and MPL should interpolate so that the above could
be written as

    struct make_vehicle
    {
        template< typename T > struct result
        {
            typedef vehicle* type;
        };

        template< typename T >
        vehicle* operator()(identity<T>, vehicle* ptr) const
        {
            return new T(ptr);
        }
    };

    int main()
    {
        vehicle* result = fusion::fold(
              fusion::identity_view< mpl::vector<vehicle,car,bicycle,train>
>()
            , static_cast<vehicle*>(0)
            , make_vehicle
            );

        return 0;
    }
</digression>

HTH,
Aleksey


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk