C++ 我是否可以检测C+;中是否存在成员函数并可供朋友访问+;?
我正试图从中吸取并应用这些想法,但我遇到了一些麻烦。我有以下定义:C++ 我是否可以检测C+;中是否存在成员函数并可供朋友访问+;?,c++,windows,templates,c++11,sfinae,C++,Windows,Templates,C++11,Sfinae,我正试图从中吸取并应用这些想法,但我遇到了一些麻烦。我有以下定义: #define HAS_MEM_FUNC(func, name) \ template<typename T, typename Sign> \ struct name {\ typedef char yes[1];
#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;\
}
然而,当我补充这一点时:
class SubWnd : public MainWnd
{
public:
friend class RegisterHandlers<SubWnd>;
SubWnd()
{
RegisterHandlers<SubWnd>::registerHandlers(this);
}
protected:
void onPaint(PaintMessage&) { /* do some stuff */ }
};
所以,我有两个问题:
如果相关的话,我将尝试在Visual Studio 2013预览编译器上执行此操作。这个问题的动机是,我正在试验C++11功能和Windows API包装器,并试图看看是否有比大型vTable和消息映射宏更好的解决方案来将消息路由到适当的处理程序。这里的障碍是: 类
SubWnd
,派生自MinWnd
,声明友谊:
friend class RegisterHandlers<SubWnd>;
friend类注册处理器;
这样,RegisterHandlers::RegisterHandlers(this)
就可以注册它的
自己的受保护处理程序onPaint
以及
从MainWnd
继承的受保护处理程序onCreate
。这个
后一种注册是多余的,因为基
类MainWnd
的构造函数将已注册onCreate
。
RegisterHandlers::RegisterHandlers(WinType*)
总是要“注册”
任何窗口可能具有的所有处理程序,如果WinType
实际上没有给定的处理程序,如果
已由基类构造函数完成
但要在创建时注册,无论是否冗余,这都是受保护的成员
在MainWnd
中,registerhandler
需要成为MainWnd
的朋友。
事实并非如此:它只是SubWnd的朋友
您无法摆脱registerHandler的模板参数化
按窗口类型T
,因为您的
SFINAE方法反思
但我不得不说,这种自我反省的方法,
在本案中,这是徒劳的空谈。每个窗口类构造函数
仍然需要做一些事情来注册自己的处理程序。你想要的方式
为此,请将任务委托给RegisterHandlers::RegisterHandlers(WinType*)
,这将:
- 尝试注册任何窗口可能具有的所有处理程序
- 每当
WinType
没有处理程序时,不执行任何操作
- 当
WinType
的基类构造函数已经注册处理程序时,冗余地重新注册该处理程序,并且
- 以非冗余方式成功注册
WinType
的特定处理程序
每个窗口类型实际上(但不可避免地)需要做的唯一部分就是最后一部分。所以
关于你的两个问题:
是否可以在不公开事件处理程序的情况下执行我试图执行的操作
对。只需让每个窗口类型注册自己的处理程序
如果基类已经注册了事件处理程序,是否也可以避免重新注册事件处理程序
对。同样的答案
我理解你只是在试验,但这个试验没有希望
您在问题2后附加了第三个问题:
有没有办法判断函数是在基类中声明的,还是起源于派生类
对。如果你再咨询,
然后再咨询
就在下面,您将看到第一个解决方案检测成员函数T::mf
当mf
在T
中定义时,但当mf
被T
继承时,则没有定义,而我的
解决方案在两种情况下都检测到mf
。因此,您可以通过
如果第一个方法没有继承,mf
,这两个方法和都会知道
检测到它,第二种方法就会检测到。感谢您的回复。如果这可以实现,就不会完全是徒劳的,因为它可以摆脱成吨的冗余样板文件。只要在它的ctor中有一个名为RegisterHandler
的东西,就可以添加新的事件处理程序,而无需返回并更改ctor。冗余的重新注册对我来说是一个关键点,因为它意味着比我希望的更高的开销,但最终它不会影响正确性。我会看看这些答案,看看它们告诉我什么:)好的,到目前为止,我已经能够使用您建议的多重检查方法消除重复注册。但是,避免将事件处理程序公开的唯一方法似乎是让每个类重新定义register_xx
函数本身,这将无法达到简化样板文件的目的。似乎如果我决定走这条路,我必须接受公共事件处理程序作为一种权衡。
class SubWnd : public MainWnd
{
public:
friend class RegisterHandlers<SubWnd>;
SubWnd()
{
RegisterHandlers<SubWnd>::registerHandlers(this);
}
protected:
void onPaint(PaintMessage&) { /* do some stuff */ }
};
template <typename _1> static yes &chk(type_check<Sign, &_1::func> *);
friend class RegisterHandlers<SubWnd>;