2013-07-12 151 views
1

我只是面临着一个有趣的挑战,让我们来解决它一起:如何将指针传递给模板类的成员函数?

我有一个类似的代理类:

//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并传递对象,成员函数和参数(如上面所见)。
  • 迄今为止似乎很好!

的问题是,我只是最近templetizedBroker。因此,当我将Broker类和回调信息传递给ConnectionHandler时,我不得不提供特定的(和无用的)模板参数。你看到问题了吗?其实一边试图generalizeBroker,我不得不specializeConnectionHandler!通过它自己的ConnectionHandler,Broker模板参数没有其他业务。

我想如果你能帮助我更好的建议传递函数指针ConnectionHandler而不涉及经纪模板参数,它会让我的一天:)

谢谢

回答

2

我相信两个选项是:

  1. 从充当一个接口,定义了用于通过ConnectionHandler作为虚拟functi核心功能的非模板基类派生的Broker模板附件。然后Broker模板将覆盖这些功能。 ConnectionHandler只能用于指向新基类的指针(在ConnectionHandler实现中不再有模板参数)。缺点:可能性能较差,因为进入Broker的呼叫将不得不经过一个额外的解引用级别。

  2. 使ConnectionHandler成为模板,并采用与Broker相同的参数。缺点:对于模板参数的每个组合,您将需要一个单独的ConnectionHandler实例。从你展示的代码来看,这不会是一个问题,但。

    下面是一个简短的代码示例,显示了如何在初始化时导出ConnectionHandler的模板参数。这是通过实现功能模板make_connectionhandler完成的,该功能模板以一个代理(任何类型)作为参数,然后使用与Broker匹配的模板参数创建ConnectionHandler。这工作,因为函数模板(而不是类模板)可以从他们给出的参数推断出他们的模板参数:

    /* 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中。

+0

jogojapan,谢谢你的建议。选项-1:似乎是一个非常好的解决方案。我会尝试一下并回复你。选项-2:在我的尸体:)因为ConnectionHandler将成为我的核心库的一部分。经纪人也是如此!这就是为什么我将它推广以便人们可以创建子类并为其虚拟功能提供定义。如果在创建Broker子类的同时有一种方法可以为模板化的ConnectionHandler自动指定参数类型,那么这个选项也会回答我的需求。 – rahman

+0

哦,所以你会接受使'ConnectionHandler'成为一个模板,如果只有模板参数会在初始化时自动推断出来?这可以做... – jogojapan

+0

@rahman你可以使用C++ 11吗? – jogojapan

相关问题