#c #templates #callback #c 17 #std-function
Вопрос:
Я работаю над классом шаблона обратного вызова, в котором обратный вызов является не функцией или функтором, а ссылкой на класс. В зависимости от контекста обратный вызов вызывается путем вызова определенного метода из зарегистрированного класса, примерно реализованного следующим образом:
template<typename T>
class callback
{
public:
// ctors, moves, copies, assignments, ...
template<typename F, typename ... A>
void invoke(F method_ptr, A ... args)
{
(*m_interface_ptr.*method_ptr)(std::forward<A>(args) ...);
}
private:
T * m_interface_ptr;
};
Теперь использование такого шаблона выглядит примерно так:
struct intf
{
virtual void method_a() { ... }
virtual void method_b(int n) { ... }
};
intf i;
callback<intf> c;
c.subscribe(i);
c.invoke(amp;intf::method_a);
c.invoke(amp;intf::method_b, 7);
Этот код работает просто отлично, но та часть, где я вызываю метод из ссылки на класс, кажется немного странной. Проблемы возникают, если я пытаюсь расширить callback
класс для поддержки как обратных вызовов ссылок на классы, так и обратных вызовов функторов или простых функций.
Существует ли стандартный способ хранения ссылки на класс и вызова методов на нем? Что-то вроде std::function
, но поддерживающее мое дело.
Пример использования #1: Вызов метода из сохраненной ссылки на класс
intf i;
// Create some std:: reference wrapper which allows custom method calls by name
std::some_ref_callable ri(i);
// Pass into callback and invoke
callback<std::some_callable<intf>> ci(ri);
ci.invoke(amp;intf::method_b, 7);
Пример использования № 2: Вызов лямбды
auto l = []{ /* generic lambda */ };
callback<decltype(l)> cf(l);
cf.invoke();
Пример использования #3: Вызов простой функции
void func(int n){ /* plain function with param */ }
callback<decltype(func)> cf(func);
cf.invoke(1337);
Возможная пользовательская реализация будет выглядеть примерно так:
template<typename T>
struct some_ref_callable
{
template<typename R, typename ... A>
auto operator ()(R(T:: * method_ptr)(A ...), A ... args)
{
return (*m_object_ptr.*method_ptr)(std::forward<A>(args) ...);
}
T * m_object_ptr = nullptr;
};
Комментарии:
1. С чем
callback_intf
и как это связано, если вообще связаноintf
?2. Похоже , вам, возможно , захочется посмотреть
std::invoke
, но трудно сказать с таким неполным примером.3. Что вы подразумеваете под «обратными вызовами функтора или простой функции»? Не могли бы вы показать примеры всех вариантов использования, которые вы хотите использовать?
4. @IgorTandetnik Извините, я изменил имя и забыл отредактировать остальную часть примера кода. Исправлю вопрос, также с примерами, которые вы просили.
5. Вы могли бы обеспечить две перегрузки для
invoke
. Что-то вродеtemplate<typename R, typename... Params, typename ... A> void invoke(R (T::*method_ptr)(Params...), A ... args)
плюс обычная ванильtemplate <typename... Args> void invoke(Args...);