gpt4 book ai didi

c++ - 与函数指针、__cdecl 和模板的混淆

转载 作者:行者123 更新时间:2023-12-01 14:47:34 25 4
gpt4 key购买 nike

在 Visual Studio 2019 中,我编写了以下测试代码,但结果让我感到困惑。

#include <iostream>
using namespace std;

template<class T, class Func>
int call(T x, Func f) { return f(x); }

int square(int x) { return x * x; }

int main() {

int (*func0) (int) = square; // line 0, OK
//int (func1)(int) = square; // line 1, wrong

int (__cdecl *func1) (int) = square; // line 2, OK
//int (__cdecl func2)(int) = square; // line 3, wrong

cout << ((int(__cdecl*)(int)) square)(5) << endl; // line 4, OK
//cout << ((int(__cdecl)(int)) square)(5) << endl; // line 5, wrong

cout << call<int, int (*)(int)>(5, square) << endl; // line 6, OK
//cout << call<int, int ()(int)>(5, square) << endl; // line 7, wrong

cout << call<int, int(__cdecl*)(int)>(5, square) << endl; // line 8, OK
cout << call<int, int(__cdecl)(int)>(5, square) << endl; // line 9, OK

return 0;
}

(我知道在使用 call 时我可以省略类型,但这是一个实验。)

我以为我能够理解从第 0 行到第 7 行的所有内容。我想到的是 square是一个函数指针,所以它的类型应该是 int (*) (int)或者 int(__cdecl*) (int) ,并且这两个相同或可以相互转换(我没有更改项目的调用约定,因此默认为 __cdecl )。

然而,令我惊讶的是第 8 行和第 9 行都能正确编译和运行。为什么会发生这种情况?

通过将第 6、7 行与第 8、9 行进行比较,我认为问题来自添加 __cdecl ,但在 Microsoft Docs没有提到这样的事情。

然后我打印出类型:

// ...
cout << typeid(square).name() << endl; // output: int __cdecl(int)
cout << typeid(*square).name() << endl; // output: int __cdecl(int)
cout << typeid(&square).name() << endl; // output: int(__cdecl*)(int)

cout << (typeid(square) == typeid(int(*) (int))) << endl; // output: false
cout << (typeid(square) == typeid(int(__cdecl) (int))) << endl; // output: true
cout << (typeid(square) == typeid(int(__cdecl*) (int))) << endl; // output: false

cout << (typeid(square) == typeid(*square)) << endl; // output: true
// ...

看来 square确实有类型 int (__cdecl) (int) .另外,我不明白为什么 square*square是同一种类型...

有人可以向我解释这些现象吗?

最佳答案

square*square是相同的类型,因为函数会衰减到指针,就像数组一样,除了(就像数组一样)在某些上下文中。特别是,衰减在 typeid 下被抑制和 & ,但不低于 * , 所以 typeid(square)为您提供 square 的类型, int (__cdecl)(int) , 而 typeid(*square)意味着 typeid(*&square)意味着 typeid(square)给出同样的东西。这导致了一个奇怪的事实,即您可以编写尽可能多的 * s 随心所欲,他们什么都不做:*************squaresquare 相同.

现在,对于您的问题的其余部分,您写的类型“函数取 int 返回 int”是错误的。 int ()(int)意思是“函数不带参数返回函数带 int 返回 int”。您想要的 int(int) .然后这有效:

cout << call<int, int(int)>(5, square) << "\n"; // line 7, fixed (FYI: endl is not normally necessary)

因为现在 call有参数列表 (int x, int f(int)) , 并且函数类型的参数声明自动调整为具有指向函数类型的指针,使得 call<int, int(int)>功能与 call<int, int (*)(int)> 相同. (这不适用于变量声明或强制转换,因此第 1、3、5 行仍然不正确。)额外的括号导致类型被误解。第 9 行有效,因为放置 __cdecl括号内使它们不会被误解(它们不是函数声明符,而是分组符号)。
cout << call<int, int (__cdecl)(int)>(5, square) << "\n"; // line 9, OK

再次, call的类型的参数进行了调整。 int (__cdecl f)(int)变成 int (__cdecl *f)(int) ,这使得第 9 行在功能上与第 8 行相同。

关于c++ - 与函数指针、__cdecl 和模板的混淆,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62438479/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com