markovd
markovd

Reputation: 33

C++ map of std::function objects throws 'failed to specialize function template' error

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 :)

Upvotes: 0

Views: 134

Answers (1)

Ted Lyngmo
Ted Lyngmo

Reputation: 118017

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

Upvotes: 1

Related Questions