由于明显的原因,在具有不同参数或返回不同类型的函数类型之间进行转换是不安全的。
(对我而言)不明显的是,在返回类型为void(且参数类型相同)的情况下,强制转换为函数指针类型是否应该安全?
是否存在一种机制,可以将例如int (*)()
强制转换为void (*)()
? static_cast
在这里失败。 reinterpret_cast
有效,但不安全。
有安全的方法吗?
std::function<void()>(funcReturningInt)
似乎可以解决问题,但我似乎无法通过迷宫实现来了解如何实现。
答案 0 :(得分:2)
按照标准,没有安全强制转换
[expr.reinterpret.cast] / 6 可以将函数指针显式转换为其他类型的函数指针。 [注意:通过指针指向与函数定义中使用的类型不同的函数类型(11.3.5)的函数的效果未定义。 -尾注],不同之处在于将“指向
T1
的指针类型的prvalue转换为指向T2
的指针的类型(其中T1
和{{1 }}是函数类型),并返回到原始类型会产生原始指针值,这种指针转换的结果未指定。
希望这会有所帮助。
答案 1 :(得分:2)
没有安全的演员。
根据c ++标准的答案由另一个答案给出,在这里我实际上要解释为什么会这样。
有多种处理返回值的方法,C / C ++没有定义或限制如何处理返回值。它们在ABI内部定义。
X86 ABI内部定义了多种调用约定,例如cdecl
,stdcall
或thiscall
。不同的调用约定对返回值的处理方式不同,这里最相关的事实是返回值存储在哪里。
如果返回值存储在堆栈中,则调用者必须在获取返回值之后调整堆栈指针。在这种情况下,如果将返回值转换为void,则调用者将无法调整堆栈指针,通常情况下,堆栈已损坏,这将导致崩溃。
如果返回值存储在寄存器中,则调用方可以假定在调用返回void的函数时未修改这些寄存器,但是如果没有,则被调用方可以修改这些寄存器。分歧也可能导致崩溃。
如果您坚持使用强制类型转换,只需确保选择正确的调用约定即可,返回值不会受到影响。
答案 2 :(得分:0)
正如其他人指出的那样,演员阵容并不安全。并且std::function
是不必要的。如果要将函数传递给期望指向void函数的指针的东西,而忽略返回结果,则可以使用lambda轻松实现:
int foo();
auto gimme_gimme_a_function_after_midnight(void (*f)() )
{
f();
}
auto test()
{
gimme_gimme_a_function_after_midnight([]() { foo(); });
}
lambda只是调用该函数,而忽略返回的值。而且由于它没有捕获,因此可以隐式转换为函数指针。
如果该函数具有易于调整的参数。
答案 3 :(得分:0)
出于完整性考虑,std :: function的实现方式是通过模板化构造函数进行的。模板化的构造函数可为请求存储的每种签名类型有效地创建静态签名适配器函数,并保留相当于存储函数的void指针和适配器函数的函数指针的值。
在调用时,它使用void指针调用适配器函数,并将其重新投射回原始类型。