将Functor作为方法传递给方法

时间:2011-03-28 20:08:27

标签: c++ templates functor

我有以下两个展示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创建一个适当调用receivedispatch的Functor。我能够创建一个简单的用例,我只需调用一个没有任何参数的方法。即。

//pseudocode
class Simple {
    void simple() {/*...*/}
}

然后我迭代:

for_each(_objects.begin(), _objects.end(), mem_fun(&Simple::simple);

不幸的是,我不知道如何将event param传递给mem_fun。看看标题,似乎我可以传递一个参数,但我不熟悉C ++来理解我需要做什么。

最后,我想让iterate方法接受一种类型的仿函数,因此它会在列表中的每个方法上触发该方法。

我宁愿避免使用Boost ...我认为这完全有可能不将此框架拖入混合体中。

谢谢!

4 个答案:

答案 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,则需要混合使用bind2ndmem_fun1。第一个绑定第二个参数(在这种情况下,您的事件;对象将是第一个),mem_fun1mem_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()来获得一个“真正的”仿函数,但你明白了。

干杯