由于显而易见的原因,在不同参数或返回不同类型的函数类型之间进行转换是不安全的。
不明显(对我来说)是否应该安全地转换为函数指针类型,其中返回类型为void(并且参数类型相同)。
有没有一种机制可以安全地施放例如int (*)()
到void (*)()
? static_cast
在这里失败了。 reinterpret_cast
工作,但不安全。
有安全的方法吗?
std::function<void()>(funcReturningInt)
似乎已经取消了这个技巧,但我似乎无法通过它的迷宫实现来了解如何。
没有安全演员阵容。
根据c ++标准给出的答案是另一个答案,在这里我想解释为什么会这样。
有不同的方法来处理返回值,C / C ++没有定义或限制如何处理返回值。它们在ABI中定义。
在X86 ABI中定义了几个调用约定,如cdecl
,stdcall
或thiscall
。不同的调用约定以不同的方式处理返回值,这里最相关的事实是存储返回值的位置。
如果返回值存储在堆栈内,则调用者必须在检索返回值后调整堆栈指针。在这种情况下,如果您将返回值转换为void,则调用者将无法调整堆栈指针,通常情况下堆栈已损坏,这通常会导致崩溃。
如果返回值存储在寄存器内,则调用者可能会在调用返回void的函数时假设这些寄存器未被修改,但如果不是,则可以通过被调用者修改这些寄存器。分歧也可能导致崩溃。
如果您坚持使用类型转换,请确保选择返回值不受影响的正确调用约定。
根据标准,没有安全演员表
[expr.reinterpret.cast] / 6函数指针可以显式转换为不同类型的函数指针。 [注意:通过指向函数类型(11.3.5)的指针调用函数的效果与函数定义中使用的类型不同是未定义的。 -end note]除了将“指向
T1
的指针”类型的prvalue转换为“指向T2
的指针”(其中T1
和T2
是函数类型)并返回其原始类型时,产生原始指针值,这样的结果指针转换未指定。
希望这可以帮助。
正如其他人所指出的,演员阵容并不安全。并且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只调用函数并忽略返回的值。并且因为它没有捕获它可以隐式地转换为函数指针。
如果函数具有易于适应的参数。
为了完整性,std :: function的方式是模板化构造函数。模板化构造函数有效地为每个请求存储的签名类型创建一个静态签名适配器函数,并保留指向存储函数的void指针和指向适配器函数的函数指针。
在调用时,它使用void指针调用适配器函数,并将其重新转换回原始类型。