Фабричная функция - шаблон

Тренируюсь, и хотел реализовать фабричную функцию - шаблон, принимающую любое количество аргументов (вариативность). Алгоритм: шаблон принимает типы - тип создаваемого класса, и тип пакет параметров. В параметрах сам пакет параметров. Создаваемые классы находятся в цепочке наследования. Код:

#include <memory>

class Base
{
public:
    virtual void run() = 0;
};

class A : public Base
{
public:
    A(int& a, int& b) {}
    void run() override {}
};


class B : public Base
{
public:
    B(int& a) {}
    void run() override {}
};

enum class ClassConst : int
{
    _A = 0,
    _B
};

template<ClassConst mt, class... Args>
auto creator(Args&&... args)
{
    std::unique_ptr<Base> result(nullptr);
    if(ClassConst::_A == mt)
        result = std::make_unique<A>(args...);
    else if(ClassConst::_B == mt)
        result = std::make_unique<B>(args...);
    return result;
};

int main()
{
    creator<ClassConst::_A>(45, 88);
    creator<ClassConst::_B>(69);
}

Код не компилируется:

  1. Конструктор B с двумя аргументами int не найден
  2. Конструктор перемещения A не может преобразовать 1 аргумент int в const A&

Хотелось бы понять, почему так происходит.


Ответы (1 шт):

Автор решения: user7860670

Тут проблема в том, что при инстанцировании creator всегда инстанцируются обе ветви - if и else и одна из них будет невалидной. Чтобы это исправить следует использовать if constexpr

Если же подобное разделение планируется повторять, то удобнее будет сделать тип-маппер из идентификатора класса в тип:

template< ClassConst x_class_id > class
TypeByIdImpl;

template<> class
TypeByIdImpl<ClassConst::_A> final { public: using type = A; };

template<> class
TypeByIdImpl<ClassConst::_B> final { public: using type = B; };

template< ClassConst x_class_id > using
TypeById = typename TypeByIdImpl<x_class_id>::type;

template<ClassConst id, typename ... Args>
auto creator(Args && ... args)
{
    return ::std::unique_ptr<Base>{::std::make_unique<TypeById<id>>(args...)};
};

Еще обычно имеет смысл форвардить аргументы.

→ Ссылка