2013-07-12 7 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. Следовательно, я был вынужден предоставить конкретные аргументы шаблона (и бесполезные) при передаче класса брокера и информации обратного вызова до ConnectionHandler. Ты видишь проблему? На самом деле, пытаясь до generalizeBroker, мне пришлось specializeConnectionHandler! ConnectionHandler, по своему усмотрению, не имеет другого бизнеса с аргументами шаблона Broker.

Я думаю, если вы могли бы мне помочь с лучшим предложением для передачи указателя функции в ConnectionHandler без привлечения аргументов шаблона брокера, это сделает мой день :)

спасибо

ответ

2

Я считаю, два варианта:

  1. Вывести Broker шаблон из не-шаблона базового класса, который действует в качестве интерфейса и определяет основные функции, которые используются в качестве виртуального ConnectionHandler functi дополнения. Затем шаблон 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.

+0

jogojapan, спасибо за ваши предложения. options-1: кажется очень приятным решением. Я просто попробую и вернусь к вам. option-2: над моим мертвым телом :) coz ConnectionHandler будет частью моей основной библиотеки. Так же и Брокер! поэтому я обобщаю его так, чтобы люди могли создавать подклассы и предоставлять определение для своих виртуальных функций. если бы был способ автоматически указывать типы аргументов для templatized ConnectionHandler в то же время, когда я создаю подкласс Broker, этот вариант также будет отвечать моим потребностям. – rahman

+0

О, так что вы согласитесь сделать шаблон «ConnectionHandler», если только аргументы шаблона будут автоматически выведены во время инициализации? Это можно сделать ... – jogojapan

+0

@rahman Можете ли вы использовать C++ 11? – jogojapan

Смежные вопросы