Como adicionar e remover std :: functions de um std :: vector [duplicar]

Sep 08 2020

Eu tenho um programa C ++ simples abaixo que registra alguns callbacks / ouvintes que são apenas std::functions. E então remove os retornos de chamada.

Código:

#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();
}

Pergunta:
O problema é que UnregisterListenernão compila e falha com o seguinte erro.

error: overload resolution selected deleted operator '=='

Mas, esta é exatamente a maneira usada para localizar e remover um item de a std::vector. Não é? O que estou fazendo errado?

No geral, minha pergunta também é para verificar se esta é a maneira correta de adicionar e remover ouvintes em C ++ usando std::functions?

Examinando esta discussão , devo armazenar o endereço real da função em vez de std:functions no std::vector?

Respostas

2 AsteroidsWithWings Sep 08 2020 at 17:45

Você não pode comparar std::functions ( exceto comnullptr ), então essa abordagem nunca funcionará ( findnão é possível localizar a função que você está procurando).

Em vez disso, envolva o std::functionem alguma classe que também tenha um ID exclusivo para cada um e, em seguida, compare-o (usando um comparador personalizado para find).

Alternativamente, e se você não se importa um pouco com a alocação dinâmica, você pode embrulhar os std::functions std::shared_ptr<>e armazená-los / repassá-los para comparação. No entanto, esteja ciente de que dois functores distintos (mas "idênticos") ainda seriam comparados como falsos neste caso, portanto, você precisa pensar cuidadosamente sobre o que está tentando alcançar e como seu código precisa ser usado.

De qualquer forma, ListenerTypedeve ser mais do que apenas um apelido.