将 Functor 作为参数传递给方法

发布于 2024-10-27 08:27:22 字数 1067 浏览 5 评论 0原文

我有以下两个展示命令模式的类。 (不幸的是,两者都有一个唯一的方法名称。)

//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 。我能够创建一个简单的用例,只需调用一个没有任何参数的方法。即

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

然后我迭代:

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

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

最终,我想让迭代方法接受一种仿函数,这样它就会在列表中的每个方法上触发该方法。

我宁愿避免 Boost...我认为这完全有可能,无需将这个框架拖入其中。

谢谢!

I have the following two classes that exhibit the Command pattern. (Unfortunately, both have a unique method name.)

//pseudocode 
class Subscriber {
    virtual void receive(const Event&) = 0;
}

class Dispatcher {
    virtual void dispatch(const Event&) = 0;
}

I have a class template that has a list of some type with a method to iterate over this list.

//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
    }
}

I would like to use mem_fun to create a Functor that calls receive or dispatch as appropriate. I'm able to create a simple use case where I simply invoke a method without any params. I.e.

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

and then I iterate:

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

Unfortunately, I have no idea how to get the event param passed to mem_fun. Looking at the headers, it does appear that I can pass a single param, but I'm not well versed in C++ to understand what I need to do.

Ultimately, I would like to make the iterate method accept a type of functor so it will fire that method on every method in the list.

I would prefer to avoid Boost...I think this is entirely possible without dragging this framework into the mix.

Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

悲念泪 2024-11-03 08:27:22

这可能是最直接的方法:

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));

This may be the most straight-forward way:

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;
};

Then:

for_each(_objects.begin(), _objects.end(), event_forwarder(event));
温柔一刀 2024-11-03 08:27:22

如果我理解正确,您想要的是 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 第二个参数具有固定值。

编辑:

要处理不同名称的调度函数,可以将调度函数作为模板参数:

//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 使调度函数成为模板参数的想法仍然有效。您甚至可以使用特征,使该机制更加灵活。

If I understand correctly, what you want is std::bind2nd:

std::for_each(_objects.begin(), _objects.end(), 
              std::bind2nd(std::mem_fun_ref(&Subscriber::receive), event));

The member-function Subscriber::receive has two parameters. The first is the implicit this pointer, and the second the const Event &. std::bind2nd, given a function f taking two arguments, returns a function f_1 taking one argument, that invokes the original function f with a fixed value for the second argument.

Edit:

To handle the different names of the dispatch functions, you can make the dispatch function a template parameter:

//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));
    }
}

Unfortunately, there does not seem to be a way to make bind2nd handle const reference parameters, so my whole solution is moot, unless copying Event objects is fine with you. This will work in C++0x with std::bind though, and the idea of making the dispatch function a template parameter is still valid. You can even use traits, to make that mechanism even more flexible.

余生再见 2024-11-03 08:27:22

您可以创建一个函子类来包装您的 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);    
    }
};

您的对象列表可以将这些函子包装器存储为 MyFunctor 实例的列表。这样您就可以对它们调用 Execute() 并让它们委托给底层类。你真的应该有一个operator()而不是Execute()来获得一个“真正的”函子,但你明白了。

干杯

You could create a functor class that wraps your Subscriber and Dispatcher classes, e.g.

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);    
    }
};

Your object list could then store these functor wrappers as a list of MyFunctor instances. This way you can call Execute() on them and let them delegate to the underlying classes. You should really have an operator() instead of Execute() to get a "real" functor, but you get the idea.

Cheers

宣告ˉ结束 2024-11-03 08:27:22

检查您是否有 tr1。如果您有 tr1,它包含 std::bind,它几乎完全等同于 boost 实现。这应该可以在 标头中找到。

如果您没有 tr1,请考虑使用 Boost。我强烈建议至少使用 boost::bind,因为它是轻量级的并且仅是标头。

如果您没有 tr1 并且不会使用 Boost,则需要混合使用 bind2ndmem_fun1。第一个绑定第二个参数(在本例中是您的事件;该对象将是第一个),并且 mem_fun1 与 mem_fun 相同,但它需要两个参数,即要调用的对象和一个用于传递被调用的成员函数的参数。但这完全是一团糟。

如果您确实可以访问bind,那么这相当容易。

for_each(objects.begin(),objects.end(),bind(&Simple::simple,_1,事件))

Check if you have tr1. If you have tr1, it contains std::bind, which is almost exactly equivalent to the boost implementation. This should be found in the <functional> header.

If you don't have tr1, consider using Boost. I would strongly suggest using at least boost::bind, as it's lightweight and header only.

If you don't have tr1 and won't use Boost, you want to mix bind2nd and mem_fun1. The first binds the second parameter (in this case, your event; the object will be the first) and mem_fun1 is the same as mem_fun, but it expects two arguments, the object to be called on and one parameter to pass the member function being called. This is a complete mess, though.

If you do have access to bind, it's fairly easy.

for_each(objects.begin(), objects.end(), bind(&Simple::simple, _1, event))

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文