I just faced an interesting challenge, let's solve it together:
I had a Broker class similar to this:
//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){}
};
and a connection handler like this:
//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
responsibilities is to deliver the incoming messages to the Broker
by calling the broker's call back function(look at ConnectionHandler::some_function
). CALL_MEMBER_FN
and pass the object,member function, and argument(s) like what you saw above. BUT
The problem is that, I just have recently templetized the Broker
. Consequently, I was forced to provide specific (and useless) template arguments when passing the Broker class and callback information to ConnectionHandler
. Do you see the problem? In fact while trying to generalize
the Broker
, I had to specialize
the ConnectionHandler
! ConnectionHandler, by its own, has got no other business with Broker template arguments.
I think If you could help me with a better suggestion for passing the function pointer to the ConnectionHandler without involving the Broker template arguments, it will make my day :)
thank you
I believe the two options are:
Derive the Broker
template from a non-template base class that acts as an interface and defines the core functions that are used by the ConnectionHandler
as virtual functions. The Broker
template would then override those functions. The ConnectionHandler
would work with pointers to the new base class only (no more template arguments in the ConnectionHandler
implementation). Drawback: Possibly slower performance as the calls into the Broker
would have to go through the one extra level of dereferencing.
Make the ConnectionHandler
a template as well, taking the same parameters as Broker
. Drawback: You will need a separate instance of ConnectionHandler
for every combination of template arguments. From the code you showed, this wouldn't be a problem, though.
Here is a brief code example that shows how the template arguments for ConnectionHandler
could be derived at initialization time. It's done by implementing a function template make_connectionhandler
, which takes a broker (of any type) as argument and then creates the ConnectionHandler
with template arguments that match those of the Broker
. This works because function templates (as opposed to class templates) can deduce their template parameters from the arguments they are given:
/* 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 }; }
Here is a main
program that shows how the make_connectionhandler
function can be used:
int main() { Broker<int> broker; auto handler = make_connectionhandler(broker); handler.handle_request(42); return 0; }
I've used C++11 syntax above. In C++03, you can't use auto
, which unfortunately means that in the declaration of handler
above, the template arguments will still appear:
ConnectionHandler<Brokern<int> > handler = make_connectionhandler(broker);
Unfortunately, there is not much you can do to avoid this completely in C++03.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.