Вектор 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;
}