我正在尝试从是否可以编写模板来检查函数的存在?并应用它们,但我遇到了一些麻烦。我定义了以下内容:
#define HAS_MEM_FUNC(func, name) \
template<typename T, typename Sign> \
struct name {\
typedef char yes[1]; \
typedef char no[2]; \
template <typename U, U> struct type_check; \
template <typename _1> static yes &chk(type_check<Sign, &_1::func> *); \
template <typename > static no &chk(...); \
static bool const value = sizeof(chk<T>(0)) == sizeof(yes); \
}
// Creates a member function detector and two overloads of a message handler
// registration function, one that registers a member function of a specific name
// if it exists and another that does nothing if that member function doesn't exist.
#define DEFINE_REGISTER_FUNC(msgid, msgtype, handlername) \
HAS_MEM_FUNC(handlername, has_##handlername);\
template <typename T>\
static void register_##handlername(\
T* pWnd, \
typename std::enable_if<has_##handlername<T, void(T::*)(msgtype&)>::value, T>::type* t = nullptr) \
{\
(void) t;\
pWnd->setMessageHandler(\
msgid,\
Handler<msgtype>(std::bind(&T::handlername, pWnd, std::placeholders::_1)));\
}\
\
template <typename T> \
static void register_##handlername(\
T* pWnd, \
typename std::enable_if<!has_##handlername<T, void(T::*)(msgtype&)>::value, T>::type* t = nullptr) \
{\
(void)pWnd;\
(void)t;\
}
我也有一个这样定义的类:
template <typename T>
class RegisterHandlers
{
public:
template <typename T>
static void registerHandlers(T* pWnd)
{
register_onCreate(pWnd);
register_onPaint(pWnd);
}
private:
DEFINE_REGISTER_FUNC(WM_CREATE, CreateMessage, onCreate);
DEFINE_REGISTER_FUNC(WM_PAINT, PaintMessage, onPaint);
};
这个想法是,如果类T
有一个成员函数onCreate(CreateMessage&)
,它会自动注册为处理程序WM_CREATE
。如果它没有这样的方法,那么register_onCreate
将调用 do-nothing 重载,编译器会很高兴。onPaint 处理程序也是如此(我将其包括在内主要是为了说明 SFINAE确实有效)。
如果我有这样的课程,这很好用:
class MainWnd
{
public:
friend class RegisterHandlers<MainWnd>;
MainWnd()
{
RegisterHandlers<MainWnd>::registerHandlers(this);
}
protected:
void onCreate(CreateMessage&) { /* do some stuff */ }
};
但是,在我添加此内容的那一刻:
class SubWnd : public MainWnd
{
public:
friend class RegisterHandlers<SubWnd>;
SubWnd()
{
RegisterHandlers<SubWnd>::registerHandlers(this);
}
protected:
void onPaint(PaintMessage&) { /* do some stuff */ }
};
我收到一个无法访问的错误MainWnd::onCreate
(无法访问受保护的成员)。我分解了宏以帮助找到问题实际发生的位置,它似乎在HAS_MEM_FUNC
宏中,可能在这一行:
template <typename _1> static yes &chk(type_check<Sign, &_1::func> *);
所以,我真的有两个问题:
- 是否可以在不公开事件处理程序的情况下做我想做的事情?
- 如果基类已经这样做了,是否也可以避免重新注册事件处理程序?换一种说法,有没有办法判断函数是在基类中声明的,还是源自派生类?
如果它是相关的,我正在尝试在 Visual Studio 2013 Preview 编译器上执行此操作。这个问题的动机是我正在试验 C++11 功能和 Windows API 包装器,我试图看看是否有比大型 vtable 和消息映射宏更好的解决方案来将消息路由到适当的处理程序。