是否可以在C ++中实现事件? [英] Is it possible to implement events in C++?

查看:77
本文介绍了是否可以在C ++中实现事件?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在C ++中实现一个C#事件,只是看我是否能做到.我被卡住了,我知道底部是错误的,但是我意识到我最大的问题是...

I wanted to implement a C# event in C++ just to see if I could do it. I got stuck, I know the bottom is wrong but what I realize my biggest problem is...

如何重载()运算符以成为T中的任何内容,在本例中为int func(float)?我不能吗我可以吗?我可以实施一个好的选择吗?

How do I overload the () operator to be whatever is in T, in this case int func(float)? I can't? Can I? Can I implement a good alternative?

#include <deque>
using namespace std;

typedef int(*MyFunc)(float);

template<class T>
class MyEvent
{
    deque<T> ls;
public:
    MyEvent& operator +=(T t)
    {
        ls.push_back(t);
        return *this;
    }
};
static int test(float f){return (int)f; }
int main(){
    MyEvent<MyFunc> e;
    e += test;
}

推荐答案

如果可以使用Boost,请考虑使用

If you can use Boost, consider using Boost.Signals2, which provides signals-slots/events/observers functionality. It's straightforward and easy to use and is quite flexible. Boost.Signals2 also allows you to register arbitrary callable objects (like functors or bound member functions), so it's more flexible, and it has a lot of functionality to help you manage object lifetimes correctly.

如果您尝试自己实施它,那么您就走对了.但是,您有一个问题:您想对每个已注册函数返回的值做些什么?您只能从operator()返回一个值,因此必须决定是不返回任何结果,还是返回其中一个结果,还是以某种方式汇总结果.

If you are trying to implement it yourself, you are on the right track. You have a problem, though: what, exactly, do you want to do with the values returned from each of the registered functions? You can only return one value from operator(), so you have to decide whether you want to return nothing, or one of the results, or somehow aggregate the results.

假设我们要忽略结果,实现起来很简单,但是如果将每个参数类型都当作一个单独的模板类型参数,则要容易一些(或者,可以使用Boost.TypeTraits之类的东西,让您轻松剖析函数类型):

Assuming we want to ignore the results, it's quite straightforward to implement this, but it's a bit easier if you take each of the parameter types as a separate template type parameter (alternatively, you could use something like Boost.TypeTraits, which allows you to easily dissect a function type):

template <typename TArg0>
class MyEvent
{
    typedef void(*FuncPtr)(TArg0);
    typedef std::deque<FuncPtr> FuncPtrSeq;

    FuncPtrSeq ls;
public:
    MyEvent& operator +=(FuncPtr f)
    {
        ls.push_back(f);
        return *this;
    }

    void operator()(TArg0 x) 
    { 
        for (typename FuncPtrSeq::iterator it(ls.begin()); it != ls.end(); ++it)
            (*it)(x);
    }
};

这要求已注册的函数具有void返回类型.为了能够接受任何返回类型的函数,可以将FuncPtr更改为

This requires the registered function to have a void return type. To be able to accept functions with any return type, you can change FuncPtr to be

typedef std::function<void(TArg0)> FuncPtr;

(或者,如果没有可用的C ++ 0x版本,请使用boost::functionstd::tr1::function).如果确实要对返回值进行某些操作,则可以将返回类型作为MyEvent的另一个模板参数.这应该相对简单些.

(or use boost::function or std::tr1::function if you don't have the C++0x version available). If you do want to do something with the return values, you can take the return type as another template parameter to MyEvent. That should be relatively straightforward to do.

使用上述实现,以下方法应该起作用:

With the above implementation, the following should work:

void test(float) { }

int main() 
{
    MyEvent<float> e;
    e += test;
    e(42);
}


允许您支持各种事件的另一种方法是对函数类型使用单个类型参数,并具有多个重载的operator()重载,每个重载都使用不同数量的参数.这些重载必须是模板,否则,如果任何重载都与事件的实际情况不符,您将得到编译错误.这是一个可行的示例:


Another approach, which allows you to support different arities of events, would be to use a single type parameter for the function type and have several overloaded operator() overloads, each taking a different number of arguments. These overloads have to be templates, otherwise you'll get compilation errors for any overload not matching the actual arity of the event. Here's a workable example:

template <typename TFunc>
class MyEvent
{
    typedef typename std::add_pointer<TFunc>::type FuncPtr;
    typedef std::deque<FuncPtr> FuncPtrSeq;

    FuncPtrSeq ls;
public:
    MyEvent& operator +=(FuncPtr f)
    {
        ls.push_back(f);
        return *this;
    }

    template <typename TArg0>
    void operator()(TArg0 a1) 
    { 
        for (typename FuncPtrSeq::iterator it(ls.begin()); it != ls.end(); ++it)
            (*it)(a1);
    }

    template <typename TArg0, typename TArg1>
    void operator()(const TArg0& a1, const TArg1& a2)
    {
        for (typename FuncPtrSeq::iterator it(ls.begin()); it != ls.end(); ++it)
            (*it)(a1, a2);
    }
};  

(我在这里使用的是C ++ 0x中的std::add_pointer,但是在Boost和C ++ TR1中也可以找到该类型修饰符;使用函数模板可以使它更简洁一些,因为您可以使用函数直接输入;您不必使用函数指针类型.)这是一个用法示例:

(I've used std::add_pointer from C++0x here, but this type modifier can also be found in Boost and C++ TR1; it just makes it a little cleaner to use the function template since you can use a function type directly; you don't have to use a function pointer type.) Here's a usage example:

void test1(float) { }
void test2(float, float) { }

int main()
{
    MyEvent<void(float)> e1;

    e1 += test1;
    e1(42);

    MyEvent<void(float, float)> e2;
    e2 += test2;
    e2(42, 42);
}

这篇关于是否可以在C ++中实现事件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆