Использование шаблонного указателя на функцию-член в качестве параметра шаблона

У меня есть этот класс:

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

Пример использования:

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

Можно ли указать что-то вместо «??? _ 1» и «??? _ 2», чтобы они могли быть любого типа? Цель состоит в том, чтобы избежать того, чтобы потребителю этого класса приходилось явно указывать DeclaringType и HandlerType, так как они могут быть легко выведены из subscribeMethod и unsubscribeMethod.

Примечание: я не могу использовать C ++ 17.

0

Решение

Можно ли указать что-то вместо «??? _ 1» и «??? _ 2», чтобы они могли быть любого типа?

Не раньше C ++ 17, нет. То, что вы запрашиваете, — это параметр не типового шаблона, который может определить его тип из предоставленного значения — именно это и является новой функцией языка C ++ 17. template auto делает.

До C ++ 17 единственный способ сделать это — сначала предоставить тип:

template <class T, T Value> struct X;

Итак, вы должны написать:

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

который, по общему признанию, отстой. Кроме того, вы можете изменить дизайн, чтобы параметры шаблона соответствовали типу класса и типу обработчика. Это позволит вам написать:

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

что в свою очередь позволит вам написать фабричную функцию:

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

И это определенно не страшно.

1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]