【发布时间】:2011-06-02 20:25:01
【问题描述】:
说要存储以下内容:
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”生成一个哈希,以便我可以正确实现== 运算符。我可以有某种唯一标识符,并要求调用者为委托提供唯一标识符,但这似乎有点麻烦并且容易出错。
有没有办法可以做到这一点?这样相同的函数将返回相同的 ID 用于比较目的吗?到目前为止,解决它的唯一方法是放弃使用std::function 的概念,转而使用支持比较的快速委托。但后来我失去了使用 lambdas 的能力。
任何帮助表示赞赏!
编辑
鉴于下面的答案,这就是我想出的......我可能错过的任何警告?我现在正在逐步完成它:
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
【问题讨论】:
-
为什么需要查找?如果您需要像这样找到 std::function,您需要根据一些标识符或类似的标识符来找到它,比如为您创建的每个新 Wrapper 自动生成一个 int。获取 int 以供将来比较,并确保每个包装器只创建一次。
-
无法比较函数,这是停机问题 (en.wikipedia.org/wiki/Halting_problem)
-
@Alexandre 我认为停机问题是相关的,但绝对不一样。我认为散列的想法是你不需要运行函数来比较它。
-
@villintehaspam,添加和迭代不是问题。但是,想要创建一个允许存储多个委托的事件类型类,如果他们愿意,也可以删除自己。将
addListener和removeListener视为此类事物的接口。 -
@Moo-Juice,在这种情况下,您将永远不会再为相同的函数生成新的包装器,因此使用我上面评论中的整数会很好。只需让 addListener 返回唯一标识符并让 removeListener 将其作为参数。