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>;