Is it possible to implement events in C++?

前端 未结 4 1338
不思量自难忘°
不思量自难忘° 2021-02-07 10:31

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...

How do I overlo

4条回答
  •  旧巷少年郎
    2021-02-07 11:24

    You absolutely can. James McNellis has already linked to a complete solution, but for your toy example we can do the following:

    #include 
    using namespace std;
    
    typedef int(*MyFunc)(float);
    
    template
    class MyEvent;
    
    template
    class MyEvent
    {
        typedef R (*FuncType)(Arg);
        deque ls;
        public:
        MyEvent& operator+=(FuncType t)
        {
                ls.push_back(t);
                return *this;
        }
    
        void operator()(Arg arg)
        {
                typename deque::iterator i = ls.begin();
                typename deque::iterator e = ls.end();
                for(; i != e; ++i) {
                        (*i)(arg);
                }
        }
    };
    static int test(float f){return (int)f; }
    int main(){
        MyEvent e;
        e += test;
        e(2.0);
    }
    

    Here I've made use of partial specialization to tease apart the components of the function pointer type to discover the argument type. boost.signals does this and more, leveraging features such as type erasure, and traits to determine this information for non-function pointer typed callable objects.

    For N arguments there are two approaches. The "easy' way, that was added for C++0x, is leveraging variadic templates and a few other features. However, we've been doing this since before that features was added, and I don't know which compilers if any, support variadic templates yet. So we can do it the hard way, which is, specialize again:

    template
    class MyEvent
    {
       typedef R (*FuncType)(Arg0, Arg1);
       deque ls;
       ...
       void operatror()(Arg0 a, Arg1)
       { ... }
       MyEvent& operator+=(FuncType f)
       { ls.push_back(f); }
       ...
    };
    

    THis gets tedious of course which is why have libraries like boost.signals that have already banged it out (and those use macros, etc. to relieve some of the tedium).

    To allow for a MyEvent style syntax you can use a technique like the following

     struct NullEvent;
    
     template
     class HisEvent;
    
    
     template<>
     struct HisEvent
     {  void operator()() {} };
    
     template
     struct HisEvent
     { void operator()(A a) {} };
    
     template
     struct HisEvent
     {
        void operator()(A a, B b) {}
     };
    
     template
     struct HisEvent
     {
         void operator()(A a, B b, C c)
         {}
     };
    
     static int test(float f){return (int)f; }
     int main(){
         MyEvent e;
         e += test;
         e(2.0);
    
         HisEvent h;
         HisEvent h2;
     }
    

    The NullEvent type is used as a placeholder and we again use partial specialization to figure out the arity.

提交回复
热议问题