Тренируюсь, и хотел реализовать фабричную функцию - шаблон, принимающую любое количество аргументов (вариативность). Алгоритм: шаблон принимает типы - тип создаваемого класса, и тип пакет параметров. В параметрах сам пакет параметров. Создаваемые классы находятся в цепочке наследования. Код:
#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);
}
Код не компилируется:
Хотелось бы понять, почему так происходит.
Тут проблема в том, что при инстанцировании 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...)};
};
Еще обычно имеет смысл форвардить аргументы.
Сборка персонального компьютера от Artline: умный выбор для современных пользователей