c++ - 如何定义类类型转换为函数指针?
问题描述
我试图了解更多的类类型转换。我正在阅读 C++ 入门 5ed。所以我试过这段代码:
int add(int x, int y) { return x + y;}
struct Foo
{
//operator(int(*)(int, int))(){return add;} // error
using pfn = int(*)(int, int);
operator pfn(){return add;} // OK
double value = 5.45;
};
int main()
{
cout << (int(*)(int, int))Foo()(5, 7) << endl; // why 1
cout << ((int(*)(int, int))Foo())(5, 7) << endl; // Ok 12
std::cout << "\nDone!\n";
}
那么为什么我不能使用类型直接为我的类定义转换,
int(*)(int, int)
但我可以使用类型别名呢?为什么我在第一个错误的语句中得到值
1
,并在第二个语句中使用括号得到正确的值?我从第一条语句中得到警告:
Description Resource Path Location Type cast to pointer from integer of different size [-Wint-to-pointer-cast] main.cpp /MyCppProj line 31 C/C++ Problem
解决方案
- 那么为什么我不能使用类型直接为我的类定义转换,
int(*)(int, int)
但我可以使用类型别名呢?
转换函数的“ TYPE”名称的语法operator
比更通用的声明符或type-id更受限制。它根本不允许使用括号,只允许使用类型说明符(如类型别名、unsigned int
、类名等)、*
、&
、&&
和const
标记volatile
的组合以及[[
属性]]
。我不能确切地说出为什么,但是像这样的复杂声明很难编写、阅读和解析。如果允许更多,在某些情况下可能存在潜在的歧义,或者他们只是不想要求编译器必须弄清楚这一点。
另外,如果允许的话,表格可能是operator int (*())(int, int);
而不是operator (int(*)(int, int))()
?或者也许这也没有意义。看?棘手。
- 为什么我在第一个错误的语句中得到值
1
,并在第二个语句中使用括号得到正确的值?
函数调用语法的优先级高于 C 风格的强制转换。所以
(int(*)(int, int))Foo()(5, 7) // (1)
(int(*)(int, int)) (Foo()(5, 7)) // (2), same as (1)
((int(*)(int, int))Foo()) (5, 7) // (3), not the same
表达式 (1) 或 (2) 通过首先创建一个临时值来评估Foo
。它后面是函数调用语法,并且Foo
没有定义operator()
,但是 C++ 还会检查它是否隐式转换为指针或对函数的引用并且确实如此,所以(5, 7)
隐式转换并将结果指针调用到add
,给出 12。这被转换为函数指针类型,该类型具有实现定义的结果。没有operator<<
声明 for 函数指针,但有一个 for bool
,并且函数指针可以隐式转换为bool
。大概奇怪的转换的结果不是空指针值,所以最终结果是true
,你会看到 value 1
。(如果你之前做过std::cout << std::boolalpha
,你应该看到true
或适当的翻译。)
除了对运算符优先级的误解之外,其中一个原因是 C 风格转换的危险,它可以做很多不同的事情,有些事情通常不是有意的。改用static_cast<int(*)(int,int)>(Foo())(5,7)
,一切都很好。或者,如果我们不小心键入static_cast<int(*)(int,int)>(Foo()(5,7))
了,编译器会给出一个关于从int
to转换的错误int(*)(int,int)
,因为只有reinterpret_cast
或 C 风格的转换可能会这样做。
- 我从第一条语句中得到警告:
Description Resource Path Location Type cast to pointer from integer of different size [-Wint-to-pointer-cast] main.cpp /MyCppProj line 31 C/C++ Problem
即使 C 风格的强制转换强制 fromint
到函数指针的转换是有效的,编译器也会警告int
没有足够的字节来表示函数指针。假设int
之前的值来自将函数指针转换为某个数字类型,这意味着要转换回来,但是每当它从足够大的类型转换为 时int
,指针值就会丢失。
推荐阅读
- java - Log4j2 DefaultRolloverStrategy 配置删除日志文件但不删除空文件夹
- javascript - 如何遍历对象数组并输出具有特定对象属性的数组javascript
- sql-server - SSIS 动态列
- python - VSCode python调试:使用模块属性时“没有名为xx的模块”
- azure - 如何使用 Azure AD Graph API 中的“备用电子邮件”属性获取用户详细信息
- ms-access - MS Access 2013 DoCmd for on click 函数返回错误
- excel - 在 VBA 中以编程方式锁定项目
- java - 如何将双值写入 JTextField?
- vue.js - 在 Vue 中与 Workbox 进行后台同步
- visual-studio-code - 自动添加空格 VS Code