c – 更改函数指针签名并将其调用以忽略返回类型是否安全?
在我们的代码库中,我们有使用(例如,std :: function< void()>)存储的回调.有时我们希望将具有不同签名的函数绑定到回调,这可以使用bind来完成.这适用于不同的函数参数,但是尝试将返回某些内容的函数绑定到期望返回void的回调不起作用,请参阅
here.
我们发现最简单的解决方案是将绑定函数的签名强制转换为具有相同参数但返回类型为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 calling conventions我可以看出返回类型是通过寄存器而不是通过堆栈传递的.我们也从不指定不同的调用约定并始终使用默认值. 假设gcc,clang和Microsoft编译器没有改变它们的行为,这是一种安全的方法来用来在绑定回调时忽略函数的返回类型吗? 解决方法
不,不是,c.f. C标准,第5.2.10节[expr.reinterpret.cast]
即使它看起来似乎在特定的编译器/平台上工作,也没有什么能保证它真正起作用(隐藏的副作用,堆栈损坏……). 你应该考虑一个新的设计,首先不需要这个演员表(如果没有更多的背景,很难回答) (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |