I have a class that encapsulates the call to a member function of a class. The beauty of this encapsulation is that I can inject operations at runtime that will be executed before or after the function call itself. Very useful for, for example, associating a log to certain calls without having to modify the original class.
A fairly simplified example of the class could be this:
template<class Type, class ReturnType, class ... Args>
class FunctionWrapper
{
public:
using FuncType = ReturnType (Type::*)(Args ...);
FunctionWrapper(FuncType function)
: m_function{function}
{ }
ReturnType operator()(Type* type, Args ... args)
{
PreOperations();
ReturnType toReturn = (type->*m_function)(args...);
PostOperations();
return toReturn;
}
private:
FuncType m_function;
void PreOperations()
{ /* ... */ }
void PostOperations()
{ /* ... */ }
};
The class in general fulfills its purpose:
struct POO
{
int func1(int a)
{ return a*2; }
void func2(int a)
{ std::cout << a; }
};
int main()
{
FunctionWrapper<POO,int,int> wrapper1(&POO::func1);
POO poo;
std::cout << wrapper1(&poo,5);
}
However, it is not perfect and it fails when the function to encapsulate has void
. So the following lines:
FunctionWrapper<POO,void,int> wrapper2(&POO::func2);
wrapper2(&poo,5);
They generate a compile-time error:
error: variable has incomplete type 'void'
ReturnType toReturn = (type->*m_function)(args...);
^
The problem is that since the template is defined at the class level I can't disable the function using SFINAE:
typename std::enable_if<std::is_same<ReturnType,void>::value,void>::type
operator()(Type* type, Args ... args)
{
PreOperations();
(type->*m_function)(args...);
PostOperations();
}
typename std::enable_if<!std::is_same<ReturnType,void>::value,ReturnType>::type
operator()(Type* type, Args ... args)
{
PreOperations();
ReturnType toReturn = (type->*m_function)(args...);
PostOperations();
return toReturn;
}
The compiler already takes care of letting me know that it doesn't buy the solution:
error: failed requirement 'std::is_same<int, void>::value'; 'enable_if' cannot be used to disable this declaration
typename std::enable_if<std::is_same<ReturnType,void>::value,void>::type
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
How can this problem be solved?