带有额外数据的函数指针

时间:2010-02-09 13:31:43

标签: c++ qt4

我有处理包的类:

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

然后我有一个接收包的服务器类。现在我想注册一个处理包的函数。但是这个函数必须有一个服务器实例用于其他变量。

所以我试试这个:

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));
}

但后来我收到了这个错误:

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

有人知道正确的解决方案吗?

1 个答案:

答案 0 :(得分:2)

您正在尝试将函数对象存储在函数指针中,而这是不可能的。您应该存储std::tr1::function代替:

#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;
};

如果你还没有访问std :: tr1的话,Boost中有一个类似的function类。

另外,考虑使用boost::bind和常规函数来避免必须创建自己的函数对象(如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也可在Boost中使用,如果您无法访问,则可以始终使用std::bind2nd

编辑:由于您无法修改FCPackageHandlerFunction的类型,您的最佳镜头可能是添加另一个存储与每个函数指针关联的数据的哈希:

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 );
}

据推测,这是您必须实施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);
}
相关问题