1

我刚刚遇到了一个有趣的挑战,让我们一起解决它:

我有一个与此类似的 Broker 类:

//Broker.h
#pragma once
#include <boost/shared_ptr.hpp>
template<class AGENT_MSG_TYPE,class BUFFER_MSG_TYPE>
class Broker
{
public:
    void messageReceiveCallback(boost::shared_ptr<ConnectionHandler>cnnHadler , std::string message){}

};

和这样的连接处理程序:

//ConnectionHandler.h
#pragma once
#include <boost/enable_shared_from_this.hpp>
#include <iostream>

//connection handler
#define CALL_MEMBER_FN(object, ptrToMember) ((object).*(ptrToMember))

template<class A,class B>
class Broker;

class ConnectionHandler: public boost::enable_shared_from_this<ConnectionHandler>
{
    typedef void (Broker<int,int>::*messageReceiveCallback)(boost::shared_ptr<ConnectionHandler>,std::string);
    messageReceiveCallback receiveCallBack;
    Broker<int,int> &theBroker;
public:

    ConnectionHandler(
            //...
            Broker<int,int>& broker,
            messageReceiveCallback callback
            //,...
            );
    void some_function(std::string incomingMessage);
};

///////////////////ConnectionHandler.cpp
#include "cnn.h"
#include "Broker.h"
ConnectionHandler::ConnectionHandler(
//...
        Broker<int,int>& broker, messageReceiveCallback callback
        //...
        ) :
        receiveCallBack(callback), theBroker(broker) {

}

void ConnectionHandler::some_function(std::string incomingMessage) {
    CALL_MEMBER_FN(theBroker, receiveCallBack)(shared_from_this(),incomingMessage);
}
  • 正如您所看到的,其中一项ConnectionHandler职责是Broker通过调用代理的回调函数(查看ConnectionHandler::some_function)将传入消息传递给。
  • 我知道调用回调函数的唯一方法是定义一个宏CALL_MEMBER_FN并传递对象、成员函数和参数,就像您在上面看到的那样。
  • 到目前为止似乎很好!

问题是,我最近刚刚Broker. 因此,在将Broker类和回调信息传递给ConnectionHandler. 你看到问题了吗?其实在尝试generalize的时候Broker,我已经到specializeConnectionHandler!ConnectionHandler 本身没有与 Broker 模板参数相关的其他业务。

我认为,如果您可以在不涉及 Broker 模板参数的情况下向我提供更好的建议,将函数指针传递给 ConnectionHandler,那会让我很开心:)

谢谢你

4

1 回答 1

2

我相信这两种选择是:

  1. Broker从充当接口的非模板基类派生模板,并定义ConnectionHandler作为虚函数使用的核心函数。然后Broker模板将覆盖这些函数。ConnectionHandler仅适用于指向新基类的指针(实现中不再有模板参数)ConnectionHandler。缺点:可能会降低性能,因为对 的调用Broker必须经过一层额外的取消引用。

  2. 也制作ConnectionHandler一个模板,参数与Broker. ConnectionHandler缺点:对于模板参数的每个组合,您都需要一个单独的实例。不过,从您显示的代码来看,这不是问题。

    这是一个简短的代码示例,显示了如何ConnectionHandler在初始化时派生模板参数。这是通过实现一个函数模板来完成的,该函数make_connectionhandler将代理(任何类型)作为参数,然后创建ConnectionHandler与模板参数匹配的Broker. 这是因为函数模板(与类模板相反)可以从给定的参数中推断出它们的模板参数:

    /* Using C++11 syntax. */
    #include <iostream>
    
    template <typename T>
    struct Broker
    {
      using type = T;
    
      void act(type token) const
      {
        std::cout << token << std::endl;
      }
    };
    
    template <typename BrokerType>
    struct ConnectionHandler
    {
    
      ConnectionHandler(const BrokerType &broker)
        : broker_(broker)
      { };
    
      void handle_request(typename BrokerType::type token)
      {
        broker_.act(token);
      }
    
    private:
      const BrokerType &broker_;
    };
    
    
    template <typename BrokerType>
    ConnectionHandler<BrokerType> make_connectionhandler(const BrokerType &broker)
    { return { broker }; }
    

    这是一个main显示如何make_connectionhandler使用该功能的程序:

    int main()
    {
      Broker<int> broker;
    
      auto handler = make_connectionhandler(broker);
    
      handler.handle_request(42);
    
      return 0;
    }
    

    我在上面使用了 C++11 语法。在 C++03 中,你不能使用auto,这很遗憾意味着在handler上面的声明中,模板参数仍然会出现:

    ConnectionHandler<Brokern<int> > handler = make_connectionhandler(broker);
    

    不幸的是,在 C++03 中您无法完全避免这种情况。

于 2013-07-12T05:57:02.543 回答