A common C ++ message bus framework and bus framework

Source: Internet
Author: User

A common C ++ message bus framework and bus framework

In the process of application development, communication between objects is often handled. Generally, communication between objects is implemented through dependency and reference of objects or interfaces, which is normal, however, if there are many objects to communicate with each other, the reference relationships between objects may be the same as those of spider networks, which may cause complicated and difficult to maintain object relationships, A good way to solve this problem is to use the message bus to decouple the tightly coupled relationship between objects referenced by each other.

Design Concept: the communication object publishes a topic to the Message bus. The topic contains the message topic, message type, and message processing function. The message topic indicates a specific topic, the message type is used to differentiate whether a topic will respond to a specific message. The message processing function is used to respond to a certain message type of the topic. When a communication object sends a specific master and a specific message to the Message bus, the bus finds the corresponding message processing function based on the message topic and message type to process the request.

Since the variable template parameters and lamda expressions of c ++ 11 are used, Compiler Nov 2012 CTP is required for compiling on windows, and GCC4.7 or above is required for linux.

Code:

# Pragma once # include <boost/tuple. hpp> # include <boost/utility. hpp> # include <boost/unordered_map.hpp> # include <boost/any. hpp> template <typename... args> struct Impl; template <typename First, typename... args> struct Impl <First, Args...> {static std: string name () {return std: string (typeid (First ). name () + "" + Impl <Args...>: name () ;}}; template <> struct Impl <> {static std: string name () {ret Urn "" ;}}; template <typename... args> std: string type_name () {return Impl <Args...>: name ();} class MessageBus: boost: noncopyable {public: // register a topic with a topic. You need to subscribe to the topic (topic, message type) and message processing function. Template <typename... TArgs, typename TObject, typename TMember> void Attach (string strTopic, TObject * Object, TMember Member) {std: function <void (TArgs...)> f = std: function <void (TArgs...)> ([=] (TArgs... arg) {(Object-> * Member) (arg ...);}); m_map.insert (make_pair (GetKey (strTopic), f);} // send a message to a topic. The topic and message type are required. After receiving the message, the message bus finds and notifies the corresponding message processing function. Template <typename... args> void SendReq (string strTopic, Args... args) {auto range = m_map.equal_range (GetKey (strTopic); boost: unordered_multimap <string, boost: any >:: iterator it; for (it = range. first; it! = Range. second; it ++) {std: function <void (Args...)> f = boost: any_cast <std: function <void (Args...)> (it-> second); f (args ...);}} // remove a topic. The topic and message type template <typename... args> void Remove (string strTopic) {auto it = m_map.find (GetKey (strTopic); while (it! = M_map.end () m_map.erase (it ++);} private: // obtain the Message key value. You can determine the observer template <typename... TArgs> string GetKey (string & strTopic) {return strTopic + type_name <TArgs...> ();} private: boost: unordered_multimap <string, boost: any> m_map ;};

Test code:

MessageBus bus; MyStruct st; bus. attach <int, string> ("bb", & st, & MyStruct: Test); // register the topic (topic, message type, message processing function) bus. attach <int, string> ("bb", & st, & MyStruct: Test2); bus. sendReq <int, string> ("bb", 0, "append"); // send a message processing request (topic and Message Type) bus. remove <int, string> ("bb"); // Remove a topic (subject and message type)

Test results:

It is a test: 0 append

It is a test2: 0 append

The updated version implements the message bus through the universal function wrapper, making interface calls more universal and consistent.

Template <typename R = void> class MessageBus: boost: noncopyable {public: // register the message template <class... args, class F, class = typename std: enable_if <! Std: is_member_function_pointer <F >:: value >:: type> void Attach (string strKey, F & f) {std: function <R (Args...)> fn = [&] (Args... args) {return f (std: forward <Args> (args )...);}; m_map.insert (std: make_pair (strKey + type_name <Args...> (), std: move (fn);} // non-const member function template <class... args, class C, class... DArgs, class P> void Attach (string strKey, R (C: * f) (DArgs ...), P & p ){ Std: function <R (Args...)> fn = [&, f] (Args... args) {return (* p. * f) (std: forward <Args> (args )...);}; m_map.insert (std: make_pair (strKey + type_name <Args...> (), std: move (fn);} template <class... args, class C, class... DArgs, class P> void Attach (string strKey, R (C: * f) (DArgs ...) const, P & p) {std: function <R (Args...)> fn = [&, f] (Args... args) {return (* p. * f) (std: forward <Args> (args )...);}; M_map.insert (std: make_pair (strKey + type_name <Args...> (), std: move (fn);} // broadcast the message. The topic and parameters can determine a message, all message recipients will receive and process the message template <typename... args> void SendReq (string strTopic, Args... args) {auto range = m_map.equal_range (strTopic + type_name <Args...> (); for (auto it = range. first; it! = Range. second; it ++) {std: function <R (Args...)> f = boost: any_cast <std: function <R (Args...)> (it-> second); f (args ...);}} // remove the message template <typename... args> void Remove (string strTopic) {string strMsgType = GetNameofMsgType <Args...> (); auto range = m_map.equal_range (strTopic + strMsgType); m_map.erase (range. first, range. second);} private: std: multimap <string, boost: any> m_map ;};

Test code:

struct A{    void Test(int x){ cout << x << endl; }    void GTest()    {        cout << "it is a test" << endl;    }    void HTest(int x) const    {        cout << "it is a HTest" << endl;    }};void GG(int x){    cout << "it is a gg" << endl;}void GG1(){    cout << "it is a GG" << endl;}void TestMessageBus(){    A a;    MessageBus<> bus;    bus.Attach<int>("aa", &A::Test, &a);    int x = 3;    bus.SendReq("aa", 3);    bus.Attach<int>("hh", &A::HTest, &a);    bus.SendReq("hh", x);    bus.Attach("bb", &A::GTest, &a);    bus.SendReq("bb");    bus.Attach<int>("gg", GG);    bus.SendReq("gg", 3);    bus.Attach("gg", GG1);    bus.SendReq("gg");}

 

Related Article

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.