Concise implementation of the event mechanism in C ++ and features that need to be abandoned

Source: Internet
Author: User
Tags eventbase

The event model is widely used, but the C ++ standard library is not ready-made. Other implementations are complex or not elegant, such as macros. Now VC11 can be used in XP, so we can pick up the advanced facilities provided by C ++ 11 to combine a lightweight implementation.

Some features need to be abandoned for concise purposes:
1. It is not supported to determine whether a function has been bound. (because std: function does not provide a comparison method, the code will increase when you implement the function)
2. the user needs to receive the returned Callback Function Identifier to remove the event binding (the same reason as above)
3. events do not return values. Advanced features such as Callback Function priority and conditional callback are not supported (for example, the maximum and minimum values of all processing results are returned, and only the event processing functions matching the specified parameters are called back)
4. Theoretically unlimited event parameters, actually limited. Generally, 0 ~ 10 parameters (VC11 does not support variable-length template parameters, but GCC does. However, the default template parameters and bitwise features can be used for simulation, So theoretically there is no limit)
5. It is not thread-safe.

Note: 3 and 5 can be flexibly supported by introducing policy modes, just like the standard library and Loki, implementing a complete event mechanism.

Simplest implementation Copy codeThe Code is as follows: # include <map>
# Include <functional>
Using namespace std;
Template <class Param1, class Param2>
Class Event
{
Typedef void HandlerT (Param1, Param2 );
Int m_handlerId;
Public:
Event (): m_handlerId (0 ){}
Template <class FuncT> int addHandler (FuncT func)
{
M_handlers.emplace (m_handlerId, forward <FuncT> (func ));
Return m_handlerId ++;
}
Void removeHandler (int handlerId)
{
M_handlers.erase (handlerId );
}
Void operator () (Param1 arg1, Param2 arg2)
{
For (const auto & I: m_handlers)
I. second (arg1, arg2 );
}
Private:
Map <int, function <HandlerT> m_handlers;
};

AddHandler forwards the callback function to std: function perfectly, enables the standard library to handle various overloading, and then returns an identifier to log out of the binding. Give it a try. The job is good:Copy codeCode: void f1 (int, int)
{
Puts ("f1 ()");
}
Struct F2
{
Void f (int, int)
{
Puts ("f2 ()");
}
Void operator () (int, int)
{
Puts ("f3 ()");
}
};
Int _ tmain (int argc, _ TCHAR * argv [])
{
Event <int, int> e;
Int id = e. addHandler (f1 );
E. removeHandler (id );
Using namespace std: placeholders;
F2 f2;
E. addHandler (bind (& F2: f, f2, _ 1, _ 2 ));
E. addHandler (bind (f2, _ 1, _ 2 ));
E. addHandler ([] (int, int ){
Puts ("f4 ()");
});
E (1, 2 );
Return 0;
}

Although there is a small drawback here, for the imitation function, if you want to use its pointer or reference, it cannot be directly bound, you need to do this:Copy codeThe Code is as follows: e. addHandler (ref (f2 ));
E. addHandler (ref (* pf2); // pf2 is a pointer to f2, but there are not many situations in which the pointer to the imitation function object is used.

What's more, in the case of Lambda expressions?
Improvement
1. Some people do not like bind, Which is troublesome to use. Put it in addhandler:Copy codeThe Code is as follows: template <class ObjT, class FuncT> int addHandler (ObjT obj, FuncT func)
{
Using namespace std: placeholders;
M_handlers.emplace (m_handlerId, std: bind (func, std: forward <ObjT> (obj), _ 1, _ 2 ));
Return m_handlerId ++;
}

2. Number of extended parameters. There is no variable-length template parameter. Here is a work und:Copy codeCode: struct NullType {};
Template <class P1 = Private: NullType, class P2 = Private: NullType>
Class Event
{
Public:
Template <class ObjT, class FuncT> int addHandler (ObjT obj, FuncT func)
{
Using namespace std: placeholders;
M_handlers.emplace (m_handlerId, std: bind (func, std: forward <ObjT> (obj), _ 1, _ 2 ));
Return m_handlerId ++;
}
Void operator () (P1 arg1, P2 arg2)
{
For (const auto & I: m_handlers)
I. second (arg1, arg2 );
}
};
Template <>
Class Event <Private: NullType, Private: NullType>
{
Public:
Template <class ObjT, class FuncT> int addHandler (ObjT obj, FuncT func)
{
Using namespace std: placeholders;
M_handlers.emplace (m_handlerId, std: bind (func, std: forward <ObjT> (obj )));
Return m_handlerId ++;
}
Void operator ()()
{
For (const auto & I: m_handlers)
I. second ();
}
};
Template <class P1>
Class Event <P1, Private: NullType>
{
Public:
Template <class ObjT, class FuncT> int addHandler (ObjT obj, FuncT func)
{
Using namespace std: placeholders;
M_handlers.emplace (m_handlerId, std: bind (func, std: forward <ObjT> (obj), _ 1 ));
Return m_handlerId ++;
}
Void operator () (P1 arg1)
{
For (const auto & I: m_handlers)
I. second (arg1 );
}
};

0 ~ Two parameters. Note that there is public code in each template and the code is extracted and put into the base class. Then, you need to open the text generator.
Complete code
Code downloadCopy codeThe Code is as follows: View Code
# Pragma once
# Include <map>
# Include <functional>
Namespace Utility
{
Namespace Private
{
Struct NullType {};
Template <class HandlerT>
Class EventBase
{
Public:
EventBase (): m_handlerId (0 ){}
Template <class FuncT> int addHandler (FuncT func)
{
M_handlers.emplace (m_handlerId, std: forward <FuncT> (func ));
Return m_handlerId ++;
}
Void removeHandler (int handlerId)
{
M_handlers.erase (handlerId );
}
Protected:
Int m_handlerId;
Std: map <int, std: function <HandlerT> m_handlers;
};
}
Template <class P1 = Private: NullType, class P2 = Private: NullType, class P3 = Private: NullType, class P4 = Private: NullType, class P5 = Private :: nullType, class P6 = Private: NullType, class P7 = Private: NullType, class P8 = Private: NullType, class P9 = Private: NullType, class P10 = Private :: nullType>
Class Event
: Public Private: EventBase <void (P1, P2, P3, P4, P5, P6, P7, P8, P9, P10)>
{
Public:
Using Private: EventBase <void (P1, P2, P3, P4, P5, P6, P7, P8, P9, P10) >:: addHandler;
Template <class ObjT, class FuncT> int addHandler (ObjT obj, FuncT func)
{
Using namespace std: placeholders;
M_handlers.emplace (m_handlerId, std: bind (func, std: forward <ObjT> (obj), _ 1, _ 2, _ 3, _ 4, _ 5, _ 6, _ 7, _ 8, _ 9, _ 10 ));
Return m_handlerId ++;
}
Void operator () (P1 arg1, P2 arg2, P3 arg3, P4 arg4, P5 arg5, P6 arg6, P7 arg7, P8 arg8, P9 arg9, P10 arg10)
{
For (const auto & I: m_handlers)
I. second (arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10 );
}
};
Template <>
Class Event <Private: NullType, Private:: NullType, Private: NullType, Private: NullType>
: Public Private: EventBase <void ()>
{
Public:
Using Private: EventBase <void () >:: addHandler;
Template <class ObjT, class FuncT> int addHandler (ObjT const obj, FuncT func)
{
M_handlers.emplace (m_handlerId, std: bind (func, obj ));
Return m_handlerId ++;
}
Void operator ()()
{
For (const auto & I: m_handlers)
I. second ();
}
};
Template <class P1>
Class Event <P1, Private: NullType, private: NullType, Private: NullType>
: Public Private: EventBase <void (P1)>
{
Public:
Using Private: EventBase <void (P1) >:: addHandler;
Template <class ObjT, class FuncT> int addHandler (ObjT obj, FuncT func)
{
Using namespace std: placeholders;
M_handlers.emplace (m_handlerId, std: bind (func, std: forward <ObjT> (obj), _ 1 ));
Return m_handlerId ++;
}
Void operator () (P1 arg1)
{
For (const auto & I: m_handlers)
I. second (arg1 );
}
};
Template <class P1, class P2>
Class Event <P1, P2, Private: NullType, Private :: nullType, Private: NullType>
: Public Private: EventBase <void (P1, P2)>
{
Public:
Using Private: EventBase <void (P1, P2) >:: addHandler;
Template <class ObjT, class FuncT> int addHandler (ObjT obj, FuncT func)
{
Using namespace std: placeholders;
M_handlers.emplace (m_handlerId, std: bind (func, std: forward <ObjT> (obj), _ 1, _ 2 ));
Return m_handlerId ++;
}
Void operator () (P1 arg1, P2 arg2)
{
For (const auto & I: m_handlers)
I. second (arg1, arg2 );
}
};
Template <class P1, class P2, class P3>
Class Event <P1, P2, P3, Private: NullType, private: NullType>
: Public Private: EventBase <void (P1, P2, P3)>
{
Public:
Using Private: EventBase <void (P1, P2, P3) >:: addHandler;
Template <class ObjT, class FuncT> int addHandler (ObjT obj, FuncT func)
{
Using namespace std: placeholders;
M_handlers.emplace (m_handlerId, std: bind (func, std: forward <ObjT> (obj), _ 1, _ 2, _ 3 ));
Return m_handlerId ++;
}
Void operator () (P1 arg1, P2 arg2, P3 arg3)
{
For (const auto & I: m_handlers)
I. second (arg1, arg2, arg3 );
}
};
Template <class P1, class P2, class P3, class P4>
Class Event <P1, P2, P3, P4, Private: NullType, Private :: nullType>
: Public Private: EventBase <void (P1, P2, P3, P4)>
{
Public:
Using Private: EventBase <void (P1, P2, P3, P4) >:: addHandler;
Template <class ObjT, class FuncT> int addHandler (ObjT obj, FuncT func)
{
Using namespace std: placeholders;
M_handlers.emplace (m_handlerId, std: bind (func, std: forward <ObjT> (obj), _ 1, _ 2, _ 3, _ 4 ));
Return m_handlerId ++;
}
Void operator () (P1 arg1, P2 arg2, P3 arg3, P4 arg4)
{
For (const auto & I: m_handlers)
I. second (arg1, arg2, arg3, arg4 );
}
};
Template <class P1, class P2, class P3, class P4, class P5>
Class Event <P1, P2, P3, P4, P5, Private: NullType>
: Public Private: EventBase <void (P1, P2, P3, P4, P5)>
{
Public:
Using Private: EventBase <void (P1, P2, P3, P4, P5) >:: addHandler;
Template <class ObjT, class FuncT> int addHandler (ObjT obj, FuncT func)
{
Using namespace std: placeholders;
M_handlers.emplace (m_handlerId, std: bind (func, std: forward <ObjT> (obj), _ 1, _ 2, _ 3, _ 4, _ 5 ));
Return m_handlerId ++;
}
Void operator () (P1 arg1, P2 arg2, P3 arg3, P4 arg4, P5 arg5)
{
For (const auto & I: m_handlers)
I. second (arg1, arg2, arg3, arg4, arg5 );
}
};
Template <class P1, class P2, class P3, class P4, class P5, class P6>
Class Event <P1, P2, P3, P4, P5, P6, Private: NullType, Private: NullType>
: Public Private: EventBase <void (P1, P2, P3, P4, P5, P6)>
{
Public:
Using Private: EventBase <void (P1, P2, P3, P4, P5, P6) >:: addHandler;
Template <class ObjT, class FuncT> int addHandler (ObjT obj, FuncT func)
{
Using namespace std: placeholders;
M_handlers.emplace (m_handlerId, std: bind (func, std: forward <ObjT> (obj), _ 1, _ 2, _ 3, _ 4, _ 5, _ 6 ));
Return m_handlerId ++;
}
Void operator () (P1 arg1, P2 arg2, P3 arg3, P4 arg4, P5 arg5, P6 arg6)
{
For (const auto & I: m_handlers)
I. second (arg1, arg2, arg3, arg4, arg5, arg6 );
}
};
Template <class P1, class P2, class P3, class P4, class P5, class P6, class P7>
Class Event <P1, P2, P3, P4, P5, P6, P7, Private: NullType>
: Public Private: EventBase <void (P1, P2, P3, P4, P5, P6, P7)>
{
Public:
Using Private: EventBase <void (P1, P2, P3, P4, P5, P6, P7) >:: addHandler;
Template <class ObjT, class FuncT> int addHandler (ObjT obj, FuncT func)
{
Using namespace std: placeholders;
M_handlers.emplace (m_handlerId, std: bind (func, std: forward <ObjT> (obj), _ 1, _ 2, _ 3, _ 4, _ 5, _ 6, _ 7 ));
Return m_handlerId ++;
}
Void operator () (P1 arg1, P2 arg2, P3 arg3, P4 arg4, P5 arg5, P6 arg6, P7 arg7)
{
For (const auto & I: m_handlers)
I. second (arg1, arg2, arg3, arg4, arg5, arg6, arg7 );
}
};
Template <class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8>
Class Event <P1, P2, P3, P4, P5, P6, P7, P8, Private: NullType, Private: NullType>
: Public Private: EventBase <void (P1, P2, P3, P4, P5, P6, P7, P8)>
{
Public:
Using Private: EventBase <void (P1, P2, P3, P4, P5, P6, P7, P8)>: addHandler;
Template <class ObjT, class FuncT> int addHandler (ObjT obj, FuncT func)
{
Using namespace std: placeholders;
M_handlers.emplace (m_handlerId, std: bind (func, std: forward <ObjT> (obj), _ 1, _ 2, _ 3, _ 4, _ 5, _ 6, _ 7, _ 8 ));
Return m_handlerId ++;
}
Void operator () (P1 arg1, P2 arg2, P3 arg3, P4 arg4, P5 arg5, P6 arg6, P7 arg7, P8 arg8)
{
For (const auto & I: m_handlers)
I. second (arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8 );
}
};
Template <class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8, class P9>
Class Event <P1, P2, P3, P4, P5, P6, P7, P8, P9, Private: NullType>
: Public Private: EventBase <void (P1, P2, P3, P4, P5, P6, P7, P8, P9)>
{
Public:
Using Private: EventBase <void (P1, P2, P3, P4, P5, P6, P7, P8, P9) >:: addHandler;
Template <class ObjT, class FuncT> int addHandler (ObjT obj, FuncT func)
{
Using namespace std: placeholders;
M_handlers.emplace (m_handlerId, std: bind (func, std: forward <ObjT> (obj), _ 1, _ 2, _ 3, _ 4, _ 5, _ 6, _ 7, _ 8, _ 9 ));
Return m_handlerId ++;
}
Void operator () (P1 arg1, P2 arg2, P3 arg3, P4 arg4, P5 arg5, P6 arg6, P7 arg7, P8 arg8, P9 arg9)
{
For (const auto & I: m_handlers)
I. second (arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9 );
}
};
} // Namespace Utility

Test code
Various binding methodsCopy codeThe Code is as follows: View Code
# Include "Event. h"
Using namespace std;
Void f1 (int, int)
{
Puts ("f1 ()");
}
Struct F2
{
F2 () {puts ("F2 construct ");}
F2 (const F2 &) {puts ("F2 copy ");}
F2 (F2 &) {puts ("F2 move ");}
F2 & operator = (const F2 &) {puts ("F2 copy assign"); return * this ;}
F2 & operator = (F2 &) {puts ("F2 move assign"); return * this ;}
Void f (int, int)
{
Puts ("f2 ()");
}
Void fc (int, int) const
{
Puts ("f2c ()");
}
};
Struct F3
{
F3 () {puts ("F3 construct ");}
F3 (const F3 &) {puts ("F3 copy ");}
F3 (F3 &) {puts ("F3 move ");}
F3 & operator = (const F3 &) {puts ("F3 copy assign"); return * this ;}
F3 & operator = (F3 &) {puts ("F3 move assign"); return * this ;}
Void operator () (int, int) const
{
Puts ("f3 ()");
}
};
Int _ tmain (int argc, _ TCHAR * argv [])
{
Utility: Event <int, int> e;
// General functions
E. addHandler (f1 );
Int id = e. addHandler (& f1 );
E. removeHandler (id); // remove the event handler
// Member functions
Using namespace std: placeholders;
F2 f2;
Const F2 * pf2 = & f2;
E. addHandler (bind (& F2: f, & f2, _ 1, _ 2); // std: bind
E. addHandler (& f2, & F2: f );
E. addHandler (pf2, & F2: fc); // constant pointer
Puts ("---- addHandler (f2, & F2: f )----");
E. addHandler (f2, & F2: f); // object copy Structure
Puts ("---- addHandler (F2 (), & F2: f )----");
E. addHandler (F2 (), & F2: f); // object transfer structure
Puts ("--------");
// Function simulation
F3 f3;
Const F3 * pf3 = & f3;
Puts ("---- addHandler (f3 )----");
E. addHandler (f3); // object copy Structure
Puts ("---- addHandler (F3 ())----");
E. addHandler (F3 (); // object transfer Construction
Puts ("--------");
E. addHandler (ref (f3); // reference a function-like object.
E. addHandler (ref (* pf3); // reference a constant object of a function.
Puts ("--------");
// Lambda expression
E. addHandler ([] (int, int ){
Puts ("f4 ()");
});
// Trigger event
E (1, 2 );
Return 0;
}

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.