Вектор std:: function <>

Скажите, что хотите сохранить следующее:

typedef std::function<void(int)> MyFunctionDecl;

.. в коллекции:

typedef std::vector<MyFunctionDecl> FunctionVector;
FunctionVector v;

Это возможно, но если я хочу найти что-то, используя std::find:

FunctionVector::const_iterator cit = std::find(v.begin(), v.end(), myFunctionDecl);

.. получаем ошибку из-за оператора ==.

Как мне было предложено в предыдущем вопросе об этом, это можно получить, инкапсулируя объявление функции внутри другого класса, который предоставляет оператор ==:

class Wrapper
{
private:
    MyFunctionDecl m_Func;

public:
    // ctor omitted for brevity

    bool operator == (const Wrapper& _rhs)
    {
         // are they equal?
    }; // eo ==
};  // eo class Wrapper

Так что я хочу сделать так, чтобы создать хэш для "MyFunctionDecl", чтобы я мог правильно реализовать оператор ==. Я мог бы иметь какой-то уникальный идентификатор и попросить вызывающего абонента предоставить уникальный идентификатор для делегата, но это кажется немного больным и подвержено ошибкам.

Есть ли способ, которым я могу это сделать? Чтобы те же функции возвращали один и тот же идентификатор для сравнительных целей? До сих пор единственный способ обойти это - отказаться от понятия использования std::function и вернуться к использованию быстрых делегатов, которые поддерживают сравнения. Но тогда я теряю способность использовать лямбды.

Любая помощь оценивается!

ИЗМЕНИТЬ

Учитывая приведенный ниже ответ, это то, что я придумал... любые предостережения, которые я, возможно, пропустил? Сейчас я пытаюсь выполнить его шаги:

class MORSE_API Event : boost::noncopyable
{
public:
    typedef std::function<void(const EventArgs&)> DelegateType;
    typedef boost::shared_ptr<DelegateType> DelegateDecl;

private:
    typedef std::set<DelegateDecl> DelegateSet;
    typedef DelegateSet::const_iterator DelegateSet_cit;
    DelegateSet m_Delegates;

public:
    Event()
    {
    };  // eo ctor


    Event(Event&& _rhs) : m_Delegates(std::move(_rhs.m_Delegates))
    {
    };  // eo mtor

    ~Event()
    {
    };  // eo dtor

    // methods
    void invoke(const EventArgs& _args)
    {
        std::for_each(m_Delegates.begin(),
                      m_Delegates.end(),
                      [&_args](const DelegateDecl& _decl) { (*_decl)(_args); });
    };  // eo invoke

    DelegateDecl addListener(DelegateType f)
    {
        DelegateDecl ret(new DelegateType(f));
        m_Delegates.insert(ret);
        return ret;
    };  // eo addListener

    void removeListener(const DelegateDecl _decl)
    {
        DelegateSet_cit cit(m_Delegates.find(_decl));
        if(cit != m_Delegates.end())
            m_Delegates.erase(cit);
    };  // eo removeListener

};  // eo class Event

Ответ 1

Посмотрели ли вы Сигналы усиления? Возможно, он уже делает то, что вы хотите сделать.

В любом случае простым способом обертывания function будет использование shared_ptr. Если вы делаете

typedef std::shared_ptr<std::function<void(int)> > MyFunctionDecl;

и убедитесь, что функция сразу же завернута внутри shared_ptr при ее создании (так что указатель уникален), указатели могут быть проверены на равенство, поэтому std::find будет работать.

Например, вы можете сделать это с помощью функции factory, например

template <class Functor>
MyFunctionDecl createDelegate(Functor f) {
    return MyFunctionDecl(new std::function<void(int)>(f));
}

Таким образом вы даете уникальный идентификатор функции (ее указателю) при создании делегата.

Кстати, я использовал бы std::set вместо std::vector, поскольку как find, так и erase являются логарифмическими, а не линейными.

Ответ 2

#include <boost/type_traits.hpp>
#include <iostream>

template<typename T>
class Wrapper
{
    private:
       T m_Func;

    public:

       template<typename U>
       bool operator==(const Wrapper<U>& _rhs)
       {
           return boost::is_same<T, U>::value;
       }
};

int main()
{
    Wrapper<int> Wint;
    Wrapper<bool> Wbool;
    std::cout << (Wint == Wbool) << std::endl;
    std::cout << (Wint == Wint) << std::endl;
}