2010-02-09 4 views
2

J'ai classe qui gère les paquets:pointeur de fonction avec des données supplémentaires

typedef void (*FCPackageHandlerFunction)(FCPackage*); 
class FCPackageHandlers{ 
    ... 
    void registerHandler(FCPackage::Type type, FCPackageHandlerFunction handler); 
    void handle(FCPackage* package); 
    ... 
    QHash<FCPackage::Type, FCPackageHandlerFunction> _handlers; 
}; 

J'ai une classe de serveur qui reçoivent des paquets. Maintenant, je veux enregistrer une fonction qui gère les paquets. Mais cette fonction doit avoir une instance du serveur pour les autres variables.

Alors j'essayez ceci:

struct FCLoginHandler{ 
    FCServer* server; 

    FCLoginHandler(FCServer* server){ 
     this->server = server; 
    } 

    void operator()(FCPackage* package){ 
     std::cout << "Received package: " << package->toString().data() << "\n"; 
    } 
}; 

... 

FCServer::FCServer(){ 
    _handlers.registerHandle(FCPackage::Login, FCLoginHandler(this)); 
} 

Mais je reçois cette erreur:

error: no matching function for call to 'FCPackageHandlers::registerHandler(FCPackage::Type, FCLoginHandler)' 
note: candidates are: void FCPackageHandlers::registerHandler(FCPackage::Type, void (*)(FCPackage*)) 

Quelqu'un sait-il la bonne solution?

Répondre

2

Vous essayez de stocker un objet fonction dans un pointeur de fonction, ce qui n'est pas possible. Vous devez stocker un std::tr1::function à la place:

#include <functional> 

typedef std::tr1::function<void(FCPackage*)> FCPackageHandlerFunction; 
class FCPackageHandlers{ 
    ... 
    void registerHandler(FCPackage::Type type, FCPackageHandlerFunction handler); 
    void handle(FCPackage* package); 
    ... 
    QHash<FCPackage::Type, FCPackageHandlerFunction> _handlers; 
}; 

Il y a une classe function similaire Boost si vous n'avez pas accès à std :: TR1 encore.

En outre, envisager d'utiliser boost::bind et une fonction régulière pour éviter le boilerplate d'avoir à créer votre propre fonction des objets tels que FCLoginHandler:

void handle_FC_login(FCServer* server, FCPackage* package) 
{ 
    std::cout << "Received package: " << package->toString().data() << "\n"; 
    // You can use server if you need it 
} 


FCServer::FCServer() 
{ 
    _handlers.registerHandle(FCPackage::Login, 
          std::tr1::bind(&handle_FC_login, this, _1)); 
} 

std::tr1::bind est également disponible dans Boost, et si vous n'avez pas accès à cela soit vous pouvez toujours utiliser std::bind2nd.

EDIT: Puisque vous ne pouvez pas modifier le type de FCPackageHandlerFunction, votre meilleur coup est peut-être ajouter un autre hachage qui stocke les données associées à chaque pointeur de fonction:

typedef void (*FCPackageHandlerFunction)(FCPackage*); 
class FCPackageHandlers{ 
    ... 
    void registerHandler(FCPackage::Type type, FCPackageHandlerFunction handler, 
         FCServer * func_data); 
    void handle(FCPackage* package); 
    ... 
    QHash<FCPackage::Type, FCPackageHandlerFunction> _handlers; 
    QHash<FCPackageHandlerFunction, FCServer*> _handler_func_data; 
}; 

// The server will be passed by the package handler which will 
// extract it from the _handler_func_data hash 
void handle_FC_login(FCServer* server, FCPackage* package) 
{ 
    std::cout << "Received package: " << package->toString().data() << "\n"; 
} 

FCServer::FCServer(){ 
    _handlers.registerHandle(FCPackage::Login, &handle_FC_login, this); 
} 

On peut supposer que c'est la façon dont vous » ll faut mettre en œuvre FCPackageHandlers::handle:

void FCPackageHandlers::handle(FCPackage * package) 
{ 
    // Query function 
    FCPackageHandlerFunction func = _handlers[package->GetType()]; 

    // Query associated data 
    FCServer * server = _handler_func_data[func]; 

    // Call handler 
    func(server, package); 
} 
+0

la chose est, je ne peux pas changer le type de FCPackageHandlerFunction. Y a-t-il une autre solution? – VDVLeon

+0

@VDVLeon - Voir mes modifications. – Manuel

Questions connexes