函数指针类型之间的转换
Converting between function pointer types
我有一个程序必须将函数存储为 void (*) (void*)
。使用该签名创建函数会导致代码重复(通常第一行是将 void 指针转换为正确的类型)并降低类型安全性(void 指针可以转换为任何类型,例如错误的类型),所以我想知道如果我可以采用 void (*)(T*)
类型的函数,然后将其转换为 void(*)(void*)
并以类似于这样的方式调用它:
#include <iostream>
#include <string>
void printer(std::string* string)
{
std::cout << *string << std::endl;
}
int main()
{
//Cast the function to a one that takes a void pointer
auto func = reinterpret_cast<void(*)(void*)>(&printer);
//Create a string and call the function with it
std::string string = "Hello World";
func(&string);
return 0;
}
上面的代码编译并运行良好(在 ideone 上),但我想知道它是否完全符合标准,或者它是否是未定义的行为并且只是针对我的特定示例和 OS 正常工作
这样做的行为是未定义的。标准(草案)说:
[expr.reinterpret.cast] A function pointer can be explicitly converted to a function pointer of a different type. [Note: The effect of
calling a function through a pointer to a function type (9.2.3.5) that is not the same as the type used in the
definition of the function is undefined. — end note] Except that converting a prvalue of type “pointer to T1”
to the type “pointer to T2” (where T1 and T2 are function types) and back to its original type yields the
original pointer value, the result of such a pointer conversion is unspecified. [Note: See also 7.3.11 for more
details of pointer conversions. — end note]
你可以使用 lambda:
void(*func)(void*) = [](void *string) {
printer(static_cast<std::string*>(string));
};
这是未定义的行为。
[expr.call]/1:
Calling a function through an expression whose function type is different from the function type of the called function's definition results in undefined behavior.
[expr.reinterpret.cast]/6:
A function pointer can be explicitly converted to a function pointer of a different type. Except that converting a prvalue of type "pointer to T1
" to the type "pointer to T2
" (where T1
and T2
are function types) and back to its original type yields the original pointer value, the result of such a pointer conversion is unspecified.
C++ 根本不允许很多函数强制转换工作,即使对于您可能认为安全的事情,例如更改 const
细节也是如此。当您需要这样的东西时,请改用显式包装函数。非捕获 lambda 可能是一种无需命名即可编写的简单方法;或者您可以定义一个通用模板,以您需要的方式包装其他函数。
[奇怪的是,C++17 允许从指向非抛出函数的指针隐式转换为指向潜在抛出函数的指针,即使 C++17 生成了这些不同的函数类型——但随后没有任何措辞我可以看到说您可以通过转换后的指针实际调用该函数。]
我有一个程序必须将函数存储为 void (*) (void*)
。使用该签名创建函数会导致代码重复(通常第一行是将 void 指针转换为正确的类型)并降低类型安全性(void 指针可以转换为任何类型,例如错误的类型),所以我想知道如果我可以采用 void (*)(T*)
类型的函数,然后将其转换为 void(*)(void*)
并以类似于这样的方式调用它:
#include <iostream>
#include <string>
void printer(std::string* string)
{
std::cout << *string << std::endl;
}
int main()
{
//Cast the function to a one that takes a void pointer
auto func = reinterpret_cast<void(*)(void*)>(&printer);
//Create a string and call the function with it
std::string string = "Hello World";
func(&string);
return 0;
}
上面的代码编译并运行良好(在 ideone 上),但我想知道它是否完全符合标准,或者它是否是未定义的行为并且只是针对我的特定示例和 OS 正常工作
这样做的行为是未定义的。标准(草案)说:
[expr.reinterpret.cast] A function pointer can be explicitly converted to a function pointer of a different type. [Note: The effect of calling a function through a pointer to a function type (9.2.3.5) that is not the same as the type used in the definition of the function is undefined. — end note] Except that converting a prvalue of type “pointer to T1” to the type “pointer to T2” (where T1 and T2 are function types) and back to its original type yields the original pointer value, the result of such a pointer conversion is unspecified. [Note: See also 7.3.11 for more details of pointer conversions. — end note]
你可以使用 lambda:
void(*func)(void*) = [](void *string) {
printer(static_cast<std::string*>(string));
};
这是未定义的行为。
[expr.call]/1:
Calling a function through an expression whose function type is different from the function type of the called function's definition results in undefined behavior.
[expr.reinterpret.cast]/6:
A function pointer can be explicitly converted to a function pointer of a different type. Except that converting a prvalue of type "pointer to
T1
" to the type "pointer toT2
" (whereT1
andT2
are function types) and back to its original type yields the original pointer value, the result of such a pointer conversion is unspecified.
C++ 根本不允许很多函数强制转换工作,即使对于您可能认为安全的事情,例如更改 const
细节也是如此。当您需要这样的东西时,请改用显式包装函数。非捕获 lambda 可能是一种无需命名即可编写的简单方法;或者您可以定义一个通用模板,以您需要的方式包装其他函数。
[奇怪的是,C++17 允许从指向非抛出函数的指针隐式转换为指向潜在抛出函数的指针,即使 C++17 生成了这些不同的函数类型——但随后没有任何措辞我可以看到说您可以通过转换后的指针实际调用该函数。]