Deidril
Deidril

Reputation: 33

C++11 Translating a variadic template to deduce a class type

i would like to generate classes from a list of class properties. For each property, the implementation is deduced through a template.

For the sake of the question i will illustrate my problem by trying to create a class to handle a virtual entity with two properties : healer and merchant

#include <iostream>

// Base class for entities
class entity
{
    public:
    virtual void do_walk() { std::cout << "I like walking" << std::endl; };
};

// A class property for healer characters
class healer
{
    public:
    // interface
    virtual void do_heal() = 0;
};

// A class property for healer npcs
class merchant
{
    public:
    // interface
    virtual void do_sell() = 0;
};

// implementation of the healer property
class healer_implementation : public healer
{
    public:
    virtual void do_heal() { std::cout << "I heal people" << std::endl; }
};



// implementation of the healer property
class merchant_implementation : public merchant
{
    public:
    virtual void do_sell() { std::cout << "I sell things" << std::endl; }
};

// To deduce the implementation of a property, we'll use the template property which will be specialized for each property and reference an implementation
template<typename T>
class property
{};

template<>
class property<merchant>
{
public: typedef merchant_implementation implementation;
};

template<>
class property<healer>
{
public: typedef healer_implementation implementation;
};


// This class is a class helper to deduce the right class type from a list of property for an entity
template<typename PROPERTY0, typename PROPERTY1=void>
class factory
{
public:
    typedef typename property<PROPERTY0>::implementation base0;
    typedef typename property<PROPERTY1>::implementation base1;


    class custom : public base0, public base1, public entity {};

};

int main()
{
    entity* bob = new factory<healer, merchant>::custom();

    // bob will try to sell things
    merchant* m = dynamic_cast<merchant*>(bob);
    if (m)
        m->do_sell();

    // bob will try to heal people
    healer* h = dynamic_cast<healer*>(bob);
    if (h)
        h->do_heal();

    // and as an entity, bob can walk
    bob->do_walk();

return 1;
}

If i execute this code, i got as expected:

I sell things
I heal people
I like walking

Now, if i want to create an entity with only one property, i must add a specialization for factory :

template<typename PROPERTY0>
class factory<PROPERTY0, void>
{
public:
    typedef typename property<PROPERTY0>::implementation base0;

    class custom : public base0, public entity {};

};

And i can test it this way :

entity* joe = new factory<merchant>::custom();
h = dynamic_cast<healer*>(joe);
if (!h)
   std::cout << "Joe is not an healer." << std::endl;


m = dynamic_cast<merchant*>(joe);
if (m)
    m->do_sell();

Then i get :

Joe is not an healer
I sell things

My question is : Is there a way to code the class factory with variadic templates to handle any number of properties, or must i have to create N specializations of factory if i need an entity with up to N properties ?

Upvotes: 3

Views: 110

Answers (1)

If you can live without the typedefs base0, base1 etc., you can indeed do this variadically:

template <class... Property>
class factory
{
public:
    typedef typename property<PROPERTY0>::implementation base0;
    typedef typename property<PROPERTY1>::implementation base1;


    class custom : public property<Property>::implementation..., public entity {};

};

[Live example]

Upvotes: 2

Related Questions