samedi 23 mai 2015

How to make template abstract factory

I was wondering how to implement template abstract factory which can produce random object out of compile time known set of classes given as template parameters. I wrote class with template methods, that gave me a solution, but I am not satisfied. I want to move base template parameter to be a factory class parameter. How can I do this?

#include <iostream>
#include <cstdlib>

class X {
public:
    virtual ~X() {}
    virtual std::string name(void) {
        return "X";
    }
};

class A : public X {
public:
    virtual ~A() {}
    virtual std::string name(void) {
        return "A";
    }
};

class B : public X {
public:
    virtual ~B() {}
    virtual std::string name(void) {
        return "B";
    }
};

class C : public X {
public:
    virtual ~C() {}
    virtual std::string name(void) {
        return "C";
    }
};

class FactoryRandom {
    template<class base>
    static base *getObjectInternal(int i) {
        return nullptr;
    }

    template<class base, class T, class... derivees>
    static base *getObjectInternal(int i) {
        return (i == 0) ? new T : getObjectInternal<base, derivees...>(--i);
    }

public:
    template<class base, class... derivees>
    static base *getObject(void) {
        const int n = sizeof...(derivees);
        return getObjectInternal<base, derivees...>(rand() % n);
    }
};

int main(int argc, char **argv) {
    for(int i = 0; i < 10; ++i) {
        std::cout << FactoryRandom::getObject<X, A, B, C>()->name() << std::endl;
    }
}

I changed class as follows, but it doesn't instantiates:

template<class base>
class FactoryRandom {
    static base *getObjectInternal(int i) {
        return nullptr;
    }

    template<class T, class... derivees>
    static base *getObjectInternal(int i) {
        return (i == 0) ? new T : getObjectInternal<derivees...>(--i);
    }

public:
    template<class... derivees>
    static base *getObject(void) {
        const int n = sizeof...(derivees);
        return getObjectInternal<derivees...>(rand() % n);
    }
};

int main(int argc, char **argv) {
    for(int i = 0; i < 10; ++i) {
        std::cout << FactoryRandom<X>::getObject<A, B, C>()->name() << std::endl;
    }
}

Error log:

../main.cpp: In instantiation of ‘static base* FactoryRandom<base>::getObjectInternal(int) [with T = C; derivees = {}; base = X]’:
../main.cpp:51:52:   recursively required from ‘static base* FactoryRandom<base>::getObjectInternal(int) [with T = B; derivees = {C}; base = X]’
../main.cpp:51:52:   required from ‘static base* FactoryRandom<base>::getObjectInternal(int) [with T = A; derivees = {B, C}; base = X]’
../main.cpp:58:33:   required from ‘static base* FactoryRandom<base>::getObject() [with derivees = {A, B, C}; base = X]’
../main.cpp:64:59:   required from here
../main.cpp:51:52: error: no matching function for call to ‘FactoryRandom<X>::getObjectInternal(int&)’
         return (i == 0) ? new T : getObjectInternal<derivees...>(--i);

Anyone help? What about java implementation?

Aucun commentaire:

Enregistrer un commentaire