Заводская модель с unique_ptr - PullRequest
0 голосов
/ 29 мая 2019

У меня есть абстрактный класс Agent и несколько производных: Predator, Prey и т. Д. Я хотел бы создать фабрику, которая дает мне unique_ptr, который я могу хранить в векторе базового класса.

Проблема в том, когдаУ меня есть:

using creatorFunctionType = std::unique_ptr<Agent>(*)();

эта часть в порядке, но на карте я не могу использовать лямбда с:

return std::make_unique<Predator>();

Но когда я пытаюсь использовать шаблон:

template <class T>
using creatorFunctionType = std::unique_ptr<T>(*)();

Остальные функции не компилируются.Я рядом уверен, я пропустил что-то важное о шаблонах, но понятия не имею, что.Можете ли вы дать мне несколько советов?

Размещение полного кода, может быть полезным

AgentFactory.h

#include "Interfaces/Agent.h"
#include "Enums.h"
#include <map>
#include <memory>

class AgentFactory
{
public:
    template <class T>
    using creatorFunctionType = std::unique_ptr<T>(*)();

    AgentFactory();
    std::unique_ptr<Agent> createAgent(Enums::AgentType agentType);
private:
    void registerAgentType(Enums::AgentType agentType, creatorFunctionType 
    creatorFunction);

    std::map<Enums::AgentType, creatorFunctionType> factoryRegister;
};

AgentFactory.cpp

#include "AgentFactory.h"
#include "Predator.h"
#include "Prey.h"

AgentFactory::AgentFactory()
{
    registerAgentType(Enums::AgentType::Predator, []() { return         
    std::make_unique<Predator>(); });
    registerAgentType(Enums::AgentType::Prey, []() { return     
    std::make_unique<Prey>(); });
}

std::unique_ptr<Agent> AgentFactory::createAgent(Enums::AgentType 
agentType)
{
    if (auto it = factoryRegister.find(agentType); it != 
    factoryRegister.end()) {
        return it->second();
    }

    return nullptr;
}

void AgentFactory::registerAgentType(Enums::AgentType agentType, 
creatorFunctionType creatorFunction)
{
    factoryRegister.insert(std::pair<Enums::AgentType, 
    creatorFunctionType>(agentType, creatorFunction));
}

Ошибки компиляции:

1>d:\predator-prey\predator-prey\agentfactory.h(15): error C2955: 'AgentFactory::creatorFunctionType': use of alias template requires template argument list
1>d:\predator-prey\predator-prey\agentfactory.h(10): note: see declaration of 'AgentFactory::creatorFunctionType'
1>d:\predator-prey\predator-prey\agentfactory.h(17): error C3203: 'creatorFunctionType': unspecialized alias template can't be used as a template argument for template parameter '_Ty', expected a real type
1>d:\predator-prey\predator-prey\agentfactory.cpp(14): error C2064: term does not evaluate to a function taking 0 arguments
1>d:\predator-prey\predator-prey\agentfactory.cpp(22): error C3203: 'creatorFunctionType': unspecialized alias template can't be used as a template argument for template parameter '_Ty2', expected a real type
1>d:\predator-prey\predator-prey\agentfactory.cpp(22): fatal error C1903: unable to recover from previous error(s); stopping compilation

1 Ответ

3 голосов
/ 29 мая 2019

Когда creatorFunctionType определяется как

using creatorFunctionType = std::unique_ptr<Agent>(*)();

creatorFunctionType - это указатель на функцию, который ожидает функции, которые возвращают std::unique_ptr<Agent>.

Однако ваши лямбдыне имеют явных возвращаемых типов, поэтому компилятор выводит их возвращаемые типы как std::unique_ptr<Predator> и std::unique_ptr<Prey>, соответственно, на основании их return операторов.

Не захватывающая лямбда неявно преобразуется в указатель-to-function, что вам и нужно в этом случае, однако ваши лямбды не возвращают std::unique_ptr<Agent>, поэтому их нельзя назначить на creatorFunctionType.Типы просто не совпадают.

Вам необходимо четко указать тип возвращаемого значения ваших лямбд, чтобы они соответствовали правильной сигнатуре, которую ожидает creatorFunctionType, например:

AgentFactory::AgentFactory()
{
    registerAgentType(Enums::AgentType::Predator,
        []() -> std::unique_ptr<Agent> { return std::make_unique<Predator>(); }
    );
    registerAgentType(Enums::AgentType::Prey,
        []() -> std::unique_ptr<Agent> { return std::make_unique<Prey>(); }
    );
}

СВ приведенном выше коде лямбды теперь будут возвращать std::unique_ptr<Agent>, удовлетворяя ожиданиям creatorFunctionType.И операторы return по-прежнему работают как есть, потому что std::unique_ptr<T> можно инициализировать с помощью std::unique_ptr<U>, если U происходит от T, что верно в вашем случае, поскольку Predator и Prey являются производнымиот Agent.

...