在我们的代码库中,我们有使用(例如std::function<void()>
)存储的回调。有时我们希望将具有不同签名的函数绑定到回调,这可以使用 bind 来完成。这对于不同的函数参数很好,但是尝试将返回某些内容的函数绑定到期望返回 void 的回调不起作用,请参见此处。
我们找到的最简单的解决方案是将绑定函数的签名转换为具有相同参数但返回类型为 void 的函数:
#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;
}
这已经使用Visual Studio 2013 November CTP、cygwin clang 3.4.2和cygwin gcc 4.8.3进行了测试,并且适用于所有平台,但调用已转换为不同函数签名的函数指针是未定义的行为。
我知道某些调用约定可能会破坏它,但据我从Microsoft调用约定中可以看出,返回类型是通过寄存器而不是通过堆栈传递的。我们也从不指定不同的调用约定并始终使用默认值。
假设gcc、clang和Microsoft编译器不改变它们的行为,这是一种在绑定回调时忽略函数返回类型的安全方法吗?