我构建的路由器的语法类似于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);
}
}