Search code examples
c++c++11stdvectorstd-function

How to add an remove std::functions from a std::vector


I have a simple C++ program below which registers some callbacks/listeners which are just std::functions. And then it removes the callbacks.

Code:

#include <iostream>
#include <functional>
#include <vector>
#include <memory>

class SomeClass {
public:
    typedef std::function<void(int)> ListenerType;
    std::vector<ListenerType> m_listeners;

    void RegisterListener(const ListenerType& listener) {
       m_listeners.push_back(listener);
    }

    void UnregisterListener(const ListenerType& listener) {
        // This does not compile. Is this the right way to remove an std::function from va ector of  std::functions?
        auto position= std::find(m_listeners.begin(), m_listeners.end(), listener);
        if (position != m_listeners.end()) {
            m_listeners.erase(position);
        }
    }
};


class SomeOtherClass : public std::enable_shared_from_this<SomeOtherClass>{
public:
    SomeOtherClass(SomeClass some_class) : m_some_class(some_class) {   
    }

    void RegisterAllListeners() {
        m_some_class.RegisterListener(std::bind(&SomeOtherClass::ListenerMethod1, shared_from_this(), std::placeholders::_1));
        m_some_class.RegisterListener(std::bind(&SomeOtherClass::ListenerMethod2, shared_from_this(), std::placeholders::_1));
    }

    void UnregisterAllListeners() {
        m_some_class.UnregisterListener(std::bind(&SomeOtherClass::ListenerMethod1, shared_from_this(), std::placeholders::_1));
        m_some_class.UnregisterListener(std::bind(&SomeOtherClass::ListenerMethod2, shared_from_this(), std::placeholders::_1));
    }

private:
    SomeClass m_some_class;
    void ListenerMethod1(int value) {
        std::cout << "The value is: " << value << std::endl;
    }

    void ListenerMethod2(int value) {
        std::cout << "The value is: " << value << std::endl;
    }
};

int main() {
   SomeClass some_class;
   SomeOtherClass some_other_class(some_class);
   some_other_class.RegisterAllListeners();
   some_other_class.UnregisterAllListeners();
}

Question:
The issue is that UnregisterListener does not compile and fails with the following error.

error: overload resolution selected deleted operator '=='

But, this is exactly the way used to find and remove an item from a std::vector. Isnt it? What am I doing wrong?

Overall, my question is also to check whether this is the right way to add and remove listeners in C++ using std::functions?

Looking through this discussion, should I have to store the actual address of the function rather than the std:functions in the std::vector?


Solution

  • You can't compare std::functions (except with nullptr), so that approach is never going to work (find cannot locate the function you're looking for).

    Instead, wrap the std::function into some class that also has a unique ID for each one, then compare that instead (using a custom comparator for find).

    Alternatively, and if you don't mind a bit of dynamic allocation, you could wrap the std::functions in std::shared_ptr<>, and store/pass those around to compare. However, be aware that two distinct (but "identical") functors would still compare false in this case, so you need to carefully think about what you're trying to achieve and how your code needs to be used.

    Either way, ListenerType should be more than just an alias.