首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >与函数指针、__cdecl和模板混淆

与函数指针、__cdecl和模板混淆
EN

Stack Overflow用户
提问于 2020-06-17 21:14:48
回答 2查看 168关注 0票数 2

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

代码语言:javascript
复制
#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中没有提到类似的问题。

然后我打印出以下类型:

代码语言:javascript
复制
    // ...
    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是一样的.

有人能给我解释一下这些现象吗?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-06-17 22:10:37

square*square是相同的类型,因为函数就像数组一样会衰减到指针,除非(就像数组一样)在特定的上下文中。特别是,衰变在typeid&下被抑制,而在*下没有,所以typeid(square)给出了square的类型,int (__cdecl)(int)typeid(*square)的意思是typeid(*&square)意味着typeid(square)提供了相同的东西。这导致了一个奇怪的事实:您可以编写任意数量的*,而它们都将无所作为:*************squaresquare是一样的。

现在,对于剩下的问题,您编写了类型为“int返回int的函数”错误。int ()(int)的意思是“函数不带参数,返回int返回int的函数”。你想要int(int)。然后这就起作用了:

代码语言:javascript
复制
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放在括号中可以使它们不被误解(而不是函数声明器,而是成为分组符号)。

代码语言:javascript
复制
cout << call<int, int (__cdecl)(int)>(5, square) << "\n"; // line 9, OK

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

票数 2
EN

Stack Overflow用户

发布于 2020-06-17 22:01:43

行的错误:

代码语言:javascript
复制
int (func1)(int) = square; // line 1, wrong

是你错过了一个“*”,它必须是:

代码语言:javascript
复制
int (*func1)(int) = square; // line 1, wrong

代码语言:javascript
复制
//int (__cdecl func2)(int) = square; // line 3, wrong

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

需要的是

代码语言:javascript
复制
cout << ((int(__cdecl*)(int)) square)(5) << endl; // line 5, wrong
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/62438479

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档