简体   繁体   中英

Factory pattern with unique_ptr

I have abstract class Agent, and few derived: Predator, Prey etc. I would like to make a factory, that gives me unique_ptr which I can store in vector of base class.

Problem is, when I have:

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

this part is ok, but in map I cannot use lambda with:

return std::make_unique<Predator>();

But when I am trying to use template:

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

The rest of functions doesn't compile. I am nearby sure, I missed something important about templates, but no idea what. Can you give me some hints?

Posting full code, may be helpful

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

Compilation errors:

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

When creatorFunctionType is defined as

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

creatorFunctionType is a pointer-to-function that expects functions which return a std::unique_ptr<Agent> .

However, your lambdas do not have explicit return types, so the compiler deduces their return types as std::unique_ptr<Predator> and std::unique_ptr<Prey> , respectively, based on their return statements.

A non-capturing lambda is implicitly convertible to a pointer-to-function, which is what you want in this case, however your lambdas do not return std::unique_ptr<Agent> , so they cannot be assigned to creatorFunctionType . The types simply do not match.

You need to be explicit about the return type of your lambdas so they match the correct signature that creatorFunctionType is expecting, eg:

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

With the above code, the lambdas will now return std::unique_ptr<Agent> , satisfying what creatorFunctionType expects. And the return statements still work as-is because std::unique_ptr<T> can be initialized with a std::unique_ptr<U> as long as U derives from T , which is true in your case since Predator and Prey derive from Agent .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM