В 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
одного типа ...
Может ли кто-нибудь объяснить мне эти явления?