I have a collection of methods with varying signatures which all need the same prefix and postfix code, so I'd like to wrap each of them up neatly. I'm trying to formulate a c++11 variadic template for a generic wrapper to my member functions, and I hit trouble when deducing the return type. Auto works, but I need the return type explicitly to provide a valid return value even if I catch an exception inside the wrapper when executing the wrappee.
So far I managed to deduce the return type for a plain wrapper function using std::result_of and I got correct behaviour for non static member functions using auto. I tried for two days now to make the std::result_of approach work for member functions, also tried a lot of variations of decltype and declval, but with no luck so far. I am running out of ideas on how to deduce the return type.
This is my working example
#include <iostream>
int foo(int a, int b) { return a + b; }
int bar(char a, char b, char c) { return a + b * c; }
template<typename Fn, typename... Args>
typename std::result_of<Fn&(Args... )>::type
wrapFunc(Fn f, Args... args) {
//Do some prefix ops
typename std::result_of<Fn&(Args... )>::type ret = f(std::forward<Args>(args)...);
//Do some suffix ops
return ret;
}
class MemberWithAuto {
private:
public:
MemberWithAuto() {};
int foo(int i, int j) { return i + j;}
template<typename Fn, typename... Args>
auto wrapper(Fn f, Args... args) {
//Do some prefix ops
auto ret = (*this.*f)(std::forward<Args>(args)...);
//Do some suffix ops
return ret;
}
};
int main() {
std::cout << "FuncWrapper for foo with 1 + 2 returns " << wrapFunc<decltype(foo)>(foo, 1, 2) << std::endl;
std::cout << "FuncWrapper for bar with 'a' + 'b' * 1 returns " << wrapFunc<decltype(bar)>(bar, 'a','b', 1) << std::endl;
MemberWithAuto meau = MemberWithAuto();
std::cout << "MemberFunction with Auto with 6 + 1 returns " << meau.wrapper(&MemberWithAuto::foo, 6, 1) << std::endl;
return 0;
}
Both of these work well, but the wrapper method using auto doesn't get me the return type for later use. I tried lots of variations with std::result:of and decltype with the following code, but I can't get it to compile correctly
#include <iostream>
int foo(int a, int b) { return a + b; }
int bar(char a, char b, char c) { return a + b * c; }
class MemberWithDecl {
private:
public:
MemberWithDecl() {};
int foo(int i, int j) { return i + j;}
template<typename Fn, typename... Args>
typename std::result_of<Fn&(Args... )>::type wrapper(Fn f, Args... args) {
//Do some prefix ops
typename std::result_of<Fn&(Args... )>::type ret = (*this.*f)(std::forward<Args>(args)...);
//Do some suffix ops
return ret;
}
};
int main() {
MemberWithDecl medcl = MemberWithDecl();
std::cout << "MemberFunction with declaration also works " << medcl.wrapper(&MemberWithDecl::foo, 6, 1) << std::endl;
return 0;
}
I was expecting to find a solution where the signature of Fn with Args... is correctly recognized, because auto also successfully deduces the types. My type declaration does not seems to find a matching template though, no matter the variations I tried, I get
error: no matching function for call to ‘MemberWithDecl::wrapper(int (MemberWithDecl::*)(int, int), int, int)’
If I leave the wrapper's return type to be auto and just try my declaration for the variable ret within, I get
error: no type named ‘type’ in ‘class std::result_of<int (MemberWithDecl::*&(int, int))(int, int)>’
typename std::result_of<Fn&(Args... )>::type ret = (*this.*f)(std::forward<Args>(args)...);
After reading the standard, I think this means that result_of does not regard Fn&(Args... ) to be well-formed, but I don't know how the correct form should look like.
Any help would be much appreciated