Вектор std :: function <> - PullRequest
       24

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

14 голосов
/ 03 января 2011

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

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 и вернуться к использованию быстрых делегатов, которые поддерживают сравнения. Но тогда я теряю способность использовать лямбды.

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

EDIT

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

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

Ответы [ 2 ]

7 голосов
/ 03 января 2011

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

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

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

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

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

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

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

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

0 голосов
/ 03 января 2011
#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;
}
...