There is a function
template<typename Class, typename MemberFuncPtr>
auto makeCallback( Class* a, MemberFuncPtr func )
{
return [a, func]( auto&&... args )
{
return ( a->*func )( std::forward<decltype( args )>( args )... );
};
}
that converts an object pointer and its member method into a lambda capturing them that can be called later just with method’s arguments. It works fine except for one situation, where the method is virtual and overridden in a derived class, e.g.
#include <iostream>
struct Base
{
virtual void g( int, int ) const
{
std::cout << "Base" << std::endl;
}
};
struct Derived : Base
{
virtual void g( int, int ) const override
{
std::cout << "Derived" << std::endl;
}
};
template<typename Class, typename MemberFuncPtr>
auto makeCallback( Class* a, MemberFuncPtr func )
{
return [a, func]( auto&&... args )
{
return ( a->*func )( std::forward<decltype( args )>( args )... );
};
}
int main()
{
Derived d;
auto cb = makeCallback( &d, &Base::g );
cb( 1, 2 );
return 0;
}
Here inspite of makeCallback( &d, &Base::g )
the program prints ‘Derived’.
Is there a way to modify only makeCallback
(including any change of its signature) to receive ‘Base’ in program output?
You might do, with some change:
template<typename Class, typename MemberFuncPtr>
auto makeCallback( Class* a, MemberFuncPtr func )
{
return [a, func]( auto&&... args )
{
return std::invoke(func, a, std::forward<decltype( args )>( args )... );
};
}
int main()
{
Derived d;
auto cb = makeCallback(&d, [](auto obj, auto&&... args){ obj->Base::g(args...); });
cb( 1, 2 );
}