Comment ajouter une suppression de fonctions std :: à partir d'un std :: vector [duplicate]

Sep 08 2020

J'ai un programme C ++ simple ci-dessous qui enregistre quelques callbacks / écouteurs qui ne sont que des std::functions. Et puis il supprime les rappels.

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:
Le problème est qu'il UnregisterListenerne se compile pas et échoue avec l'erreur suivante.

error: overload resolution selected deleted operator '=='

Mais, c'est exactement la manière utilisée pour rechercher et supprimer un élément d'un fichier std::vector. N'est-ce pas? Qu'est-ce que je fais mal?

Dans l'ensemble, ma question est également de vérifier si c'est la bonne façon d'ajouter et de supprimer des écouteurs en C ++ en utilisant std::functions?

En parcourant cette discussion , devrais-je avoir à stocker l'adresse réelle de la fonction plutôt que le std:functions dans le std::vector?

Réponses

2 AsteroidsWithWings Sep 08 2020 at 17:45

Vous ne pouvez pas comparer std::functions ( sauf avecnullptr ), donc cette approche ne fonctionnera jamais ( findimpossible de localiser la fonction que vous recherchez).

Au lieu de cela, enveloppez le std::functiondans une classe qui a également un ID unique pour chacun, puis comparez-le à la place (en utilisant un comparateur personnalisé pour find).

Sinon, et si cela ne vous dérange pas un peu d'allocation dynamique, vous pouvez envelopper les std::functions std::shared_ptr<>et les stocker / les transmettre pour les comparer. Cependant, sachez que deux foncteurs distincts (mais "identiques") se compareraient toujours à false dans ce cas, vous devez donc réfléchir attentivement à ce que vous essayez de réaliser et à la manière dont votre code doit être utilisé.

Quoi qu'il en soit, cela ListenerTypedevrait être plus qu'un simple alias.