Witam

Mój kolega przedłożył mi następujący problem do rozwiązania:

Zaimplementować szablonową fabrykę obiektów, która przyjmuje jako argumenty szablonowe typy: bazowy, oraz dowolną ilość typów pochodnych.
Fabryka powinna zwracać losowo obiekt z puli typów pochodnych.

Rozwiązałem to w następujący sposób:

#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;
    }
}

Wszystko działa jak należy, jednak nie podoba mi się to, że do argumentów szablonu metod muszę przekazywać typ bazowy.
Chciałem to przepisać tak, aby typ bazowy był przekazywany jako argument szablonowy klasy, nie metod:

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;
    }
}

Jednak kompilator twierdzi, że do instancjalizacji brakuje mu metody ‘FactoryRandom<X>::getObjectInternal(int&)’, która przecież jest zaimplementowana:

../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);

Proszę o podpowiedzi.

Pozdrawiam