хранение указателей на функции-члены разных классов на одной карте - PullRequest
0 голосов
/ 29 сентября 2018

Я создал маршрутизатор, который по синтаксису похож на маршрутизатор 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 для реализации лучшего решения, но я не знаю как.

вот полная реализация: маршрутизатор.ч

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