在单个映射中存储不同类的成员函数指针

时间:2018-09-29 09:27:54

标签: c++ qt callback member-function-pointers

我构建的路由器的语法类似于laravel的路由器,用于路由QWebsocket消息

成员函数指针必须为空,并且必须具有Message引用参数,并且我将回调和实例存储在名为MemberCallbackInfo的结构中。

class CNTRLR{}; // a dummy class

using MemberCallback = void (CNTRLR::*)(Message &);

struct MemberCallbackInfo
{
    CNTRLR *instance;
    MemberCallback ptr;
};

然后我正在使用模板函数,以便我可以通过任何函数传递任何类,只要函数签名与参数匹配即可

template <class T> 
static void get ( const QString& action,
                  T *instance,
                  void (T::*ptr)(Message &) )

要实际存储实例和回调,我必须像这样执行reinterpret_cast

    MemberCallbackInfo obj={
    reinterpret_cast<CNTRLR *>(instance),
    reinterpret_cast<MemberCallback>(ptr)
};
callBacks->insert(action, obj); //callbacks is QMap<QString,MemberCallbackInfo>

现在,如果我想注册一个回调,我只需要这样做

Route::post("user/auth", ControllerInstance, &AuthController::authenticate);

此实现在gcc上运行良好,我甚至对其进行了调整以使其在MSVC 2017上运行,因此它确实运行良好。 但是我仍然想知道……至少在不需要使用reinterpret_cast的情况下,有没有更好的方法来实现这种路由器。 我在Qt项目上使用了此类,因此我认为可以利用他们的Metaobject系统来实现更好的解决方案,但是我不知道如何。

这是完整的实现: router.h

#ifndef ROUTER_H
#define ROUTER_H

#include <QObject>
#include "message.h"


#ifdef Q_CC_MSVC
#pragma pointers_to_members(full_generality,virtual_inheritance)
#endif

class CNTRLR{}; //MSVC will throw C2440 when using reinterpret_cast with undefined classes

using MemberCallback = void (CNTRLR::*)(Message &);

struct MemberCallbackInfo
{
    CNTRLR *instance;
    MemberCallback ptr;
};

typedef QMap<QString,MemberCallbackInfo> MemberCallbacks;

class Router : public QObject
{
    Q_OBJECT
public:
    explicit Router(QObject *parent = nullptr);
    void route(Message &message);

    template <class T> static void registerRoute(MemberCallbacks *callBacks,
                                          const QString& action,
                                                 T *instance,
                                                 void (T::*ptr)(Message &))
    {
        MemberCallbackInfo obj={reinterpret_cast<CNTRLR *>(instance),
                                reinterpret_cast<MemberCallback>(ptr)};
        callBacks->insert(action, obj);
    }
    template <class T> static void get   (const QString& action, T *instance, void (T::*ptr)(Message &))
    {
        registerRoute(&getRoutes,action,instance,ptr);
    }
    template <class T> static void post  (const QString& action, T *instance, void (T::*ptr)(Message &))
    {
        registerRoute(&postRoutes,action,instance,ptr);
    }


private:
    static MemberCallbacks getRoutes;
    static MemberCallbacks postRoutes;
};

typedef Router Route;

#endif // ROUTER_H

router.cpp

    #include "router.h"

MemberCallbacks Router::getRoutes;
MemberCallbacks Router::postRoutes;

Router::Router(QObject *parent) : QObject(parent)
{

}

void Router::route(Message &message)
{
    if(message.method()=="GET")
    {
        MemberCallbackInfo cb= getRoutes.value(message.action());
        (cb.instance->*cb.ptr)(message);
    }
    else if(message.method()=="POST")
    {
        MemberCallbackInfo cb= postRoutes.value(message.action());
        (cb.instance->*cb.ptr)(message);
    }
}

0 个答案:

没有答案