我有以下两个展示Command模式的类。 (不幸的是,两者都有一个独特的方法名称。)
//pseudocode
class Subscriber {
virtual void receive(const Event&) = 0;
}
class Dispatcher {
virtual void dispatch(const Event&) = 0;
}
我有一个类模板,其中包含某种类型的列表,其中包含迭代此列表的方法。
//pseudocode
template<typename T>
class Registry {
typedef list<T> ObjectList;
ObjectList _objects;
void iterate(const Event& event) {
for_each(_objects.begin(), _objects.end(), ...); //not sure what to do here
}
}
我想使用mem_fun
创建一个适当调用receive
或dispatch
的Functor。我能够创建一个简单的用例,我只需调用一个没有任何参数的方法。即。
//pseudocode
class Simple {
void simple() {/*...*/}
}
然后我迭代:
for_each(_objects.begin(), _objects.end(), mem_fun(&Simple::simple);
不幸的是,我不知道如何将event
param传递给mem_fun。看看标题,似乎我可以传递一个参数,但我不熟悉C ++来理解我需要做什么。
最后,我想让iterate
方法接受一种类型的仿函数,因此它会在列表中的每个方法上触发该方法。
我宁愿避免使用Boost ...我认为这完全有可能不将此框架拖入混合体中。
谢谢!
答案 0 :(得分:6)
这可能是最直接的方式:
class event_forwarder // make private in Registry
{
public:
event_forwarder(const Event& event) :
mEvent(event)
{}
void operator()(Subscriber& subcriber) const
{
subscriber.receive(mEvent);
}
void operator()(Dispatcher& dispatcher) const
{
dispatcher.dispatch(mEvent);
}
private:
const Event& mEvent;
};
然后:
for_each(_objects.begin(), _objects.end(), event_forwarder(event));
答案 1 :(得分:4)
如果我理解正确,你想要的是std::bind2nd
:
std::for_each(_objects.begin(), _objects.end(),
std::bind2nd(std::mem_fun_ref(&Subscriber::receive), event));
成员函数Subscriber::receive
有两个参数。第一个是隐式this
指针,第二个是const Event &
。 std::bind2nd
,给定一个带有两个参数的函数f
,返回一个带有一个参数的函数f_1
,它调用原始函数f
,并为第二个参数赋予固定值。 / p>
修改强>
要处理调度函数的不同名称,可以使调度函数成为模板参数:
//pseudocode
template<typename T, void (T::*dispatch_method)(Event)>
class Registry {
typedef list<T> ObjectList;
ObjectList _objects;
void iterate(const Event& event) {
std::for_each(_objects.begin(), _objects.end(),
std::bind2nd(std::mem_fun_ref(dispatch_method), event));
}
}
不幸的是,似乎没有办法让bind2nd
处理const
参考参数,所以我的整个解决方案没有实际意义,除非复制Event
对象很好你将。这将在C ++ 0x中使用std::bind
,并且使调度函数成为模板参数的想法仍然有效。您甚至可以使用特征,使该机制更加灵活。
答案 2 :(得分:0)
检查您是否有tr1。如果你有tr1,它包含std::bind
,几乎完全等同于boost
实现。这应该在<functional>
标题中找到。
如果您没有tr1,请考虑使用Boost。我强烈建议至少使用boost::bind
,因为它只是轻量级和标题。
如果您没有tr1且不使用Boost,则需要混合使用bind2nd
和mem_fun1
。第一个绑定第二个参数(在这种情况下,您的事件;对象将是第一个),mem_fun1
与mem_fun
相同,但它需要两个参数,即要调用的对象和传递被调用的成员函数的一个参数。但这完全是一团糟。
如果您有权访问bind
,则相当容易。
for_each(objects.begin(), objects.end(), bind(&Simple::simple, _1, event))
答案 3 :(得分:0)
您可以创建一个包装Subscriber和Dispatcher类的仿函数类,例如
class MyFunctor {
public:
virtual void Execute(const Event& event) = 0;
};
class MySubscriberFunctor : public MyFunctor {
private:
Subscriber subscriber_;
public:
void Execute(const Event& event) {
subscriber_.receive(event);
}
};
class MyDispatcherFunctor : public MyFunctor {
private:
Dispatcher dispatcher_;
public:
void Execute(const Event& event) {
dispatcher_.dispatch(event);
}
};
然后,您的对象列表可以将这些functor包装器存储为MyFunctor实例的列表。这样你就可以对它们调用Execute()并让它们委托给底层的类。你应该有一个operator()而不是Execute()来获得一个“真正的”仿函数,但你明白了。
干杯