0

I'm having hard time solving this issue related to my C++ school project. Basically, I need a map where the key is given GUID and the value is a member function of MyClass, which is a factory method for instances of derived classes of BaseClass, returned as a BaseClass pointer. The code would look like this:

class MyClass{
private:
    std::map<GUID, std::function<BaseClass*(ClassX*, ClassY*, const GUID*)>> map;
    template<typename T>
    BaseClass* createInstance(ClassX* classX, ClassY* classY, const GUID* guid);
public:
    BaseClass* getDerivedInstance(ClassX* classX, ClassY* classY, const GUID* guid);
    //...
};

Factory method:

template<typename T>
BaseClass* MyClass::createInstance(ClassX* classX, ClassY* classY, const GUID* guid){
    return new T(classX, classY, guid);
}

Method to call factory from the map:

BaseClass* MyClass::getInstance(ClassX* classX, ClassY* classY, const GUID* guid){
    return map[*guid](classX, classY, guid);
}

In constructor, i fill the map with factory methods (for now with just one) like this:

map[classGuid] = std::bind<BaseClass*>(&MyClass::createInstance<DerivedClassX>, this, std::placeholders::_3);

Class MyClass is a singleton, so it is filled just once.Code doesn't show any errors, but when compiled, MSVS2019 throws following errors:

'std::invoke': no matching overloaded function found Failed to specialize function template 'unknown-type std::invoke(_Callable &&,_Types &&...) noexcept()'

I even tried doing something like

using plain_fnc = BaseClass* (MyClass::*)(ClassX*, ClassY*, const GUID*);
using bind_eq = decltype(std::bind<BaseClass*>(std::declval<plain_fnc>(),
    std::declval<MyClass*>(), std::declval<const decltype(std::placeholders::_3)&>()));

bind_eq factory = std::bind<BaseClass*>(&MyClass::createInstance<DerivedClassX>, this, std::placeholders::_3);
map[classGuid] = factory;

, which also doesn't show any errors, but ends with the same result when compiled. I spent a few hours trying to solve this, but have no clue what could be the issue.Any help/tips greatly appreciated :)

1 Answer 1

1

You forgot the first placeholders:

map[classGuid] = std::bind<BaseClass*>(&MyClass::createInstance<DerivedClassX>, this,
    std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);

You could also use a lambda:

map[classGuid] = [this](ClassX* classX, ClassY* classY, const GUID* guid) {
                     return createInstance<DerivedClassX>(classX, classY, guid);
                 };

Demo

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you! I was under the impression that using std::placeholders_3 will work for 3 function parameters and didn't know, that it is just for the third parameter. Works fine now.
@markovd You're welcome! Using a lambda is probably the most popular way to do this nowadays. It's somewhat easier to read too i.m.o.

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.