Search code examples
c++observer-pattern

std::fuction calling convention


I've have observer implementation in my code. It looks like this:

template <typename... Args>
class Event {
    std::map<size_t, std::function<void(Args...)>> m_observers;
    mutable std::mutex m_mutex;
public:
    virtual ~Event() = default;

    [[nodiscard]] size_t Register(const size_t& object_id, std::function<void(Args...)> observer) {

        std::lock_guard<std::mutex> lk(m_mutex);
        m_observers[object_id] = observer;
        return object_id;
    }

I don't add full class code here for brevity. And the code that connects objects:

class Object {
    std::wstring m_name;
    size_t m_id=0;
public:
    Object() { GenerateID(); }
    Object(std::wstring name) : m_name(name) { GenerateID(); }
    virtual ~Object() = default;

    size_t GetID() const { return m_id; }

    template <class T, typename... Args>
    size_t ObjectConnect(void(T::* callback_fn)(Args...args), Event<Args...>* obj_event);

    template <typename... Args>
    size_t ObjectConnect(std::function<void> fn(Args...args), Event<Args...>* obj_event);
private:
    void GenerateID();
};

template<class T, typename... Args>
size_t Object::ObjectConnect(void(T::* callback_fn)(Args... args), Event<Args...>* obj_event) {
    auto fn = [this, callback_fn](Args... args)->void {((static_cast<T*>(this))->*callback_fn)(args...); };
    return obj_event->Register(m_id, fn);
}

template<typename ...Args>
inline size_t Object::ObjectConnect(std::function<void> fn(Args...args), Event<Args...>* obj_event)
{
    return obj_event->Register(m_id, fn);
}

First type of ObjectConnect function works perfectly with member functions of child classes. I've added second overload to be able to pass member functions with additional parameters:

std::function<void(bool)> fn1 = [this, serverName](bool param) {this->OnServerConnection(serverName.toStdWString(), param); };
    ObjectConnect(fn1, Refactoring::Backend::GetManagerByName(serverName.toStdWString())->GetConnectionEvent());

Sadly it gives me next error:

Error   C2784   'size_t Design::Object::ObjectConnect(std::function<void> (__cdecl *)(Args...),Design::Event<Args...> *)': could not deduce template argument for 'std::function<void> (__cdecl *)(Args...)' from 'std::function<void (bool)>'

From error message it seems like it has something to do with calling convention, but I can't figure out what to do and googling haven't given me any clues.


Solution

  • This is unrelated to calling convention: all member functions have the same calling convention in C++ (sometimes called “thiscall”), and std::function<T>::operator() is a member function.

    Instead, the issue is that your function prototype for a function taking a std::function<T> is incorrect. The signature goes in the template argument list, like so:

    template <typename... Args>
    size_t ObjectConnect(std::function<void(Args...)> fn, Event<Args...>* obj_event);