Я хотел бы функцию, которая сочетает в себе различные аспекты вышеупомянутых трех функций [...]
Если я правильно понимаю, что вы хотите ... Мне кажется, чтовозможно, но я вижу только запутанное решение.
Надеясь, что кто-то другой может предложить более простой способ, я использовал несколько помощников: объявленная только шаблонная функция gth1()
для обнаружения Args...
изуказатель метода
template <typename ClassT, typename ... ArgsT>
constexpr auto gth1 (void(ClassT::*)(ArgsT...)) -> std::tuple<ArgsT...>;
и специализация шаблона gth2
struct со статическим методом, который создает и возвращает лямбду (с поправкой Холта: спасибо!)
template <typename, typename, auto>
struct gth2;
template <typename ClassT, typename ... ArgsT, auto memFn>
struct gth2<ClassT, std::tuple<ArgsT...>, memFn>
{
static auto getLambda (ClassT * obj)
{ return [obj](ArgsT ... args)
{ return (obj->*memFn)(std::forward<ArgsT>(args)...); }; }
};
Теперь выможно написать getCallback()
функцию следующим образом
template <auto memFn, typename ClassT>
auto getCallback (ClassT * obj)
{ return gth2<ClassT, decltype(gth1(memFn)), memFn>::getLambda(obj); }
Ниже приведен полный рабочий пример
#include <iostream>
template <typename, typename, auto>
struct gth2;
template <typename ClassT, typename ... ArgsT, auto memFn>
struct gth2<ClassT, std::tuple<ArgsT...>, memFn>
{
static auto getLambda (ClassT * obj)
{ return [obj](ArgsT ... args)
{ return (obj->*memFn)(std::forward<ArgsT>(args)...); }; }
};
template <typename ClassT, typename ... ArgsT>
constexpr auto gth1 (void(ClassT::*)(ArgsT...)) -> std::tuple<ArgsT...>;
template <auto memFn, typename ClassT>
auto getCallback (ClassT * obj)
{ return gth2<ClassT, decltype(gth1(memFn)), memFn>::getLambda(obj); }
// Example of use
struct Foo
{ void bar(size_t& x, const std::string& s) { x=s.size(); } };
int main ()
{
Foo f;
auto l { getCallback<&Foo::bar>(&f) };
size_t x;
l(x, "1234567");
std::cout << x << "\n";
}