在 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
是一个函数指针,所以它应该有 typeint (*) (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
属于同一类型...
有人可以向我解释这些现象吗?