简体   繁体   English

使用模板化的成员函数指针作为模板参数

[英]Using templated member function pointer as template parameter

I have this class: 我有这个课:

#include <assert.h>

template <typename DeclaringType, typename HandlerType>
using SubscribeMethodType = void (DeclaringType::*)(HandlerType* handler);

template <typename DeclaringType>
using UnsubscribeMethodType = void (DeclaringType::*)();

template <SubscribeMethodType<???_1, ???_2> subscribeMethod, UnsubscribeMethodType<???_1> unsubscribeMethod>
class EventHandler
{
private:
    template <typename T>
    struct ExtractDeclaringAndHandlerTypes
    {
    };

    template <typename DeclaringType, typename HandlerType>
    struct ExtractDeclaringAndHandlerTypes<void (DeclaringType::*)(HandlerType*)>
    {
        typedef DeclaringType DeclaringType;
        typedef HandlerType HandlerType;
    };

    typedef typename ExtractDeclaringAndHandlerTypes<decltype(subscribeMethod)>::DeclaringType DeclaringType;
    typedef typename ExtractDeclaringAndHandlerTypes<decltype(subscribeMethod)>::HandlerType HandlerType;

public:
    EventHandler() { }
    ~EventHandler()
    {
        Unsubscribe();
    }

    void Subscribe(DeclaringType* eventOwner, HandlerType* handler)
    {
        assert(!m_IsSubscribed);

        m_EventOwner = eventOwner;
        (eventOwner->*subscribeMethod)(handler);
        m_IsSubscribed = true;
    }

    void Unsubscribe()
    {
        if (m_IsSubscribed)
        {
            (m_EventOwner->*unsubscribeMethod)();
            m_IsSubscribed = false;
        }
    }

private:
    DeclaringType* m_EventOwner;
    bool m_IsSubscribed;
};

Example usage: 用法示例:

class IEventConsumer
{
};

class ExampleEventOwner
{
public:
    void Subscribe(IEventConsumer* consumer) {}
    void Unsubscribe() {}
};

int main()
{
    ExampleEventOwner owner;
    IEventConsumer consumer;

    EventHandler<&ExampleEventOwner::Subscribe, &ExampleEventOwner::Unsubscribe> handler;
    handler.Subscribe(&owner, &consumer);
    handler.Unsubscribe();

    return 0;
}

Is it possible to specify something instead of "???_1" and "???_2" to allow them to be any type? 是否可以指定某些内容而不是“ ??? _ 1”和“ ??? _ 2”以允许它们为任何类型? The goal is to avoid the consumer of this class having to specify DeclaringType and HandlerType explicitly, since they can easily be inferred from subscribeMethod and unsubscribeMethod. 目的是避免此类的使用者必须显式指定DeclaringType和HandlerType,因为可以轻松地从subscriptionMethod和unsubscribeMethod推断出它们。

Note: I cannot use C++17. 注意:我不能使用C ++ 17。

Is it possible to specify something instead of "???_1" and "???_2" to allow them to be any type? 是否可以指定某些内容而不是“ ??? _ 1”和“ ??? _ 2”以允许它们为任何类型?

Not before C++17, no. 不早于C ++ 17,不。 What you're asking for is a template non-type parameter that can deduce its type from the provided value - which is exactly what the new C++17 language feature template auto does. 您需要的是一个模板非类型参数,该参数可以从提供的值中推断出其类型-这正是新的C ++ 17语言功能template auto执行的操作。

Before C++17, the only way to do such a thing is to provide the type first: 在C ++ 17之前,执行此操作的唯一方法是首先提供类型:

template <class T, T Value> struct X;

So you have to write: 所以你必须写:

EventHandler<decltype(&ExampleEventOwner::Subscribe), &ExampleEventOwner::Subscribe,
    decltype(&ExampleEventOwner::Unsubscribe), &ExampleEventOwner::Unsubscribe
> handler;

which, admittedly, sucks. 当然,这很烂。 Alternatively, you could change the design to make the template parameters be the class type and handler type. 另外,您可以更改设计以使模板参数成为类类型和处理程序类型。 This would allow you to write: 这将使您可以编写:

EventHandler<ExampleEventOwner, IEventConsumer> handler(
    &ExampleEventOwner::Subscribe, &ExampleEventOwner::Unsubscribe);

which in turn would let you write a factory function: 依次可以让您编写工厂函数:

template <class T, class H>
EventHandler<void (T::*)(H*), void(T::*)()> makeEventHandler(
    void (T::*subscribe)(H*), void (T::*unsubscribe)());

auto handler = makeEventHandler(&ExampleEventOwner::Subscribe,
    &ExampleEventOwner::Unsubscribe);

And that is decidedly non-terrible. 这绝对是不可怕的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM