0

I'm trying to build a factory method with self-registration based on (https://www.codetg.com/article/7r1QnR43bm3ZogBJ.html), which registers logic operations. But I can't figure out how to convert std::make_unique to std::make_unique. I'm always getting the same error:

return': cannot convert from 'std::unique_ptr<T1,std::default_delete<_Ty>>' to 'std::unique_ptr<LogicOperation,std::default_delete<_Ty>>

I'm still a noob on the subject of unique pointer but I've read on cppreference.com

If T is a derived class of some base B, then std::unique_ptr<T> is implicitly convertible to std::unique_ptr<B>. 
The default deleter of the resulting std::unique_ptr<B> will use operator delete for B, 
leading to undefined behavior unless the destructor of B is virtual.

I have tried instead of making a lambda function,to use std::move() as shown in other examples on stackoverflow. But that does not same to work either.

main

int main()
{
    Signal a;
    Signal b;
    a.setState(1);
    b.setState(0);
    std::unique_ptr<LogicOperation> logic = LogicOperationFactory::Create("AND");
    bool x[2] = { a.getState(), b.getState() };
    bool y = logic->operation(x, 2); // do and operation
}

LogicOperation.h

class LogicOperation
{
public:
    LogicOperation() = default;
    virtual ~LogicOperation() = default;
public:
    virtual bool operation(bool*, uint8_t count) = 0;
};

LogicOperationFactory.h:

        using TCreateMethod = std::function<std::unique_ptr<LogicOperation>()>;
    template<class T1>
    static bool Register(const std::string name)
    {
        std::map<std::string, TCreateMethod>::iterator it;
        it = s_methods.find(name);

        if (it != s_methods.end())
            return false;

        s_methods[name] = []() -> std::unique_ptr<LogicOperation> {
            // Constructs an object of type T and wraps it in a std::unique_ptr
            return std::make_unique<T1>(); // use default constructor
        };

        return true;
    }

LogicAndOperation.cpp

class LogicAndOperation :
    public virtual LogicOperation
{
public:
    LogicAndOperation() = default;
    virtual ~LogicAndOperation() = default;

    bool operation(bool* signals, uint8_t count) override;
private:
    static bool s_registered;
};

bool LogicAndOperation::s_registered =
LogicOperationFactory::Register<LogicAndOperation>("AND");

Can someone please explain to me, how I can make std::unique_ptr from a derived class (LogicAndOperation)?

2
  • 2
    Please provide a minimal reproducible example. In particular: does LogicAndOperation inherit publicly and unambiguously from LogicOperation? Commented Apr 7, 2019 at 21:50
  • For instance, this compiles fine. But without a minimal and reproducible example, we can't really help. Commented Apr 7, 2019 at 22:32

1 Answer 1

0

Given the example code, I cannot see the issue.

This compiled and ran in C++14 mode (Clang 10). I filled-in some of the gaps that our example code was lacking. I cannot see your LogicOperationFactory::Create() function; is that where your issue is?

#include <cassert>
#include <cstdint>
#include <functional>
#include <iostream>
#include <map>
#include <memory>

class LogicOperation
{
public:
    virtual ~LogicOperation() = default;
    virtual bool operation(bool*, uint8_t count) = 0;
};

using TCreateMethod = std::function<std::unique_ptr<LogicOperation>()>;

class LogicOperationFactory
{
    static std::map<std::string, TCreateMethod> s_methods;

public:
    template<class T>
    static bool Register(const std::string& name)
    {
        std::map<std::string, TCreateMethod>::iterator it;
        it = s_methods.find(name);

        if (it != s_methods.end())
            return false;

        s_methods[name] = []() -> std::unique_ptr<LogicOperation> {
            // Constructs an object of type T and wraps it in a std::unique_ptr
            return std::make_unique<T>(); // use default constructor
        };

        return true;
    }

    static std::unique_ptr<LogicOperation> Create(const std::string& name)
    {
        auto iter = s_methods.find(name);
        return (iter != s_methods.end()) ? (iter->second)() : nullptr;
    }
};

std::map<std::string, TCreateMethod> LogicOperationFactory::s_methods;

class FooLogic : public LogicOperation
{
public:
    bool operation(bool*, uint8_t) override {
        std::cout << "FooLogic::operation" << std::endl;
        return true;
    }
};

class BarLogic : public LogicOperation
{
public:
    bool operation(bool*, uint8_t) override {
        std::cout << "BarLogic::operation" << std::endl;
        return true;
    }
};

static bool s_registeredFooLogic = LogicOperationFactory::Register<FooLogic>("FooLogic");
static bool s_registeredBarLogic = LogicOperationFactory::Register<BarLogic>("BarLogic");

int main() {
    assert(s_registeredFooLogic && s_registeredBarLogic);
    auto bar_logic = LogicOperationFactory::Create("BarLogic");
    bool flag = false;
    bar_logic->operation(&flag, 1);

    auto null_logic = LogicOperationFactory::Create("ThisDoesNotExist");
    assert(nullptr == null_logic);
    return 0;
}
Sign up to request clarification or add additional context in comments.

3 Comments

It looks like you've added more example code. Does your error stem from the Register function, or from the LogicOperationFactory::Create function? If it's the latter, I can't help you if I can't see it...
Added my own LogicOperationFactory::Create function .
Dear mciantyre, I've found the code that caused the error. I test your code and used it to check mine. I found out just now that an other piece of code took the wrong template argument, which cause the error. Embarrassing mistake on my part. Thanks so much for the Help!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.