In our codebase we have callbacks that are stored using (eg. std::function<void()>
). Sometimes we would like to bind a function with a different signature to the callback which can be done using bind. This is fine for different function parameters but trying to bind a function that returns something to a callback that is expecting a void return doesn't work, see here.
The simplest solution we have found is to cast the bound function's signature to a function with the same parameters but a void return type:
#include <functional>
#include <iostream>
int ReturnInt()
{
std::cout << "ReturnInt" << std::endl;
return 5;
}
struct Struct
{
int ReturnInt()
{
std::cout << "Test::Func" << std::endl;
return 30;
}
};
template<typename ReturnType, typename ... ArgumentTypes>
auto IgnoreResult(ReturnType (*i_Func)(ArgumentTypes ...))
-> void (*)(ArgumentTypes ...)
{
return reinterpret_cast<void (*)(ArgumentTypes ...)>(i_Func);
}
template<typename ReturnType, typename ClassType, typename ... ArgumentTypes>
auto IgnoreResult(ReturnType (ClassType::*i_Func)(ArgumentTypes ...))
-> void (ClassType::*)(ArgumentTypes ...)
{
return reinterpret_cast<void (ClassType::*)(ArgumentTypes ...)>(i_Func);
}
int main(int argc, char **argv)
{
std::function<void ()> BoundType;
Struct instance;
BoundType = std::bind(IgnoreResult(&Struct::ReturnInt), &instance);
BoundType();
BoundType = std::bind(IgnoreResult(&ReturnInt));
BoundType();
return 0;
}
This has been tested with Visual Studio 2013 November CTP, cygwin clang 3.4.2 and cygwin gcc 4.8.3 and works on all platforms but calling a function pointer that has been cast to a different function signature is undefined behaviour.
I know that certain calling conventions could break it but as far as I could tell from the Microsoft calling conventions the return type is passed via a register not via the stack. We are also never specifying different calling conventions and always use the defaults.
Assuming that the gcc, clang and Microsoft compilers don't change their behaviour, is this a safe method to use to ignore the return type of a function when binding a callback?
Is it safe to change a function pointers signature and call it to ignore the return type?
No, it is not, c.f. the C++ standard, section § 5.2.10 [expr.reinterpret.cast]
The effect of calling a function through a pointer to a function type (8.3.5) that is not the same as the type used in the definition of the function is undefined.
Even if it does appear to work on a particular compiler/platform, nothing guarantees you that it really does (hidden side effects, stack corruption...).
You should consider a new design where this cast is not needed in the first place (hard to answer without more context)