Я создал маршрутизатор, который по синтаксису похож на маршрутизатор 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);
}
}