Context
I want to wrap a member function and a specific object into a function object (which I'll use as a callback later). I would like to write this wrapping function once for different member functions and objects especially because my actual lambda does some extra work before calling the wrapped method. Here are a few possible implementations:
#include <iostream>
#include <string>
#include <utility>
template <class ClassT, class... ArgsT>
auto getCallbackPtr(ClassT* obj, void(ClassT::* memfn)(ArgsT...))
{
return [obj, memfn](ArgsT&&... args) {
(obj->*memfn)(std::forward<ArgsT>(args)...);
};
}
template <auto memFn, class ClassT>
auto getCallbackTemplate(ClassT* obj)
{
return [obj](auto&&... args){
return (obj->*memFn)(std::forward<decltype(args)>(args)...);
};
}
template <auto memFn, class ClassT, class... ArgsT>
auto getCallbackRedundant(ClassT* obj)
{
return [obj](ArgsT&&... args){
return (obj->*memFn)(std::forward<ArgsT&&>(args)...);
};
}
// Example of use
class Foo {
public:
void bar(size_t& x, const std::string& s) { x=s.size(); }
};
int main() {
Foo f;
auto c1 = getCallbackPtr(&f, &Foo::bar);
size_t x1; c1(x1, "123"); std::cout << "c1:" << x1 << "\n";
auto c2 = getCallbackTemplate<&Foo::bar>(&f);
size_t x2; c2(x2, "123"); std::cout << "c2:" << x2 << "\n";
auto c3 = getCallbackRedundant<&Foo::bar, Foo, size_t&, const std::string&>(&f);
size_t x3; c3(x3, "123"); std::cout << "c3:" << x3 << "\n";
}
Question (in short)
I would like a function that combines different aspects of the above three functions:
- It should takes the member function as a compile-time template parameter, unlike
getCallbackPtr()
. - Its
operator()
should not be a templated function, unlikegetCallbackTemplate()
. - Its template parameters (except the member function pointer) should inferred from the function use, unlike
getCallbackRedundant()
.
Some details
Here are my reasons for wanting the member function to be a template parameter, although I must admit these probably won't have a noticable effect in practice:
- The optimizer will probably make the call to member function directly rather than via a function pointer. In fact, as this is the only place the member function is called from, it might even be inlined into the lambda by the compiler.
- The resulting function object is smaller (one pointer rather than one pointer plus one member function pointer), and so is more likely to fit into the footprint of a
std::function
(small object optimization).
Here are the problems with the getCallbackTemplate()
, which has a templated operator()
:
- It doesn't work with Visual Studio. This is a show stopper for me. (The error is
error C3533: a parameter cannot have a type that contains 'auto'
, in reference totemplate <auto memFn, class ClassT>
.) - If the wrong types of arguments are passed in, I suspect it will have a more complicated and confusing compiler error than a non-templated
operator()
(admittedly this is just a hunch). - The templated
operator()
is not capable of accepting initializer lists for arguments. This is not an issue at all for me but I mention it for the record.
I think the reasons for wanting inferred template parameters are fairly clear: getCallbackRedundant()
is distractingly verbose and harder to use.
Can this be done? How?