In Visual Studio 2019, I have written the following test codes, but the results confused me.
#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;
}
(I am aware that I can omit the types when using call
, but this is an experiment.)
I thought I was able to understand everything from line 0 to line 7. What I had in mind is that square
is a funtion pointer, so it should have type int (*) (int)
or perhaps int(__cdecl*) (int)
, and these two are either identical or can be casted to each other (I didn't change the calling convention of the project, so the default is __cdecl
).
However, I was surprised that both line 8 and line 9 compile and run correctly. Why does this happen?
By comparing lines 6, 7 with lines 8, 9, I think the problem comes from adding __cdecl
, but in Microsoft Docs nothing like this is mentioned.
I then printed out the types:
// ...
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
// ...
It seems that square
indeed has type int (__cdecl) (int)
. Also, I don't understand why square
and *square
are of the same type...
Could someone explain these phenomena to me?