Я хочу управлять парой функций WinAPI через std::unique_ptr:
#include <memory>
int* __stdcall construct(){ return new int{5}; }
void __stdcall destruct(int* v){ delete v; }
int main() {
using Ptr = std::unique_ptr<int, void(&)(int*)>;
Ptr v(construct(), destruct);
}
Когда я создаю 64-битный двоичный файл с помощью MSVC 19.33, код работает. Если я соберу 32-битный бинарник, то будет ошибка.
example.cpp
<source>(8): error C2660: 'std::unique_ptr<int,void (__cdecl &)(int *)>::unique_ptr': function does not take 2 arguments
C:/data/msvc/14.33.31631/include\memory(3291): note: see declaration of 'std::unique_ptr<int,void (__cdecl &)(int *)>::unique_ptr'
Compiler returned: 2
Это работает с обоими, если я явно называю __stdcall в std::unique_ptr<int, void(__stdcall&)(int*)>, поэтому я предполагаю, что это часть сигнатуры функции.
Почему такая разница в 32 и 64 бит? Это ошибка в компиляторе?
Существует только одно возможное соглашение о вызовах для x64, поэтому компилятор всегда использует его.
«поэтому я предполагаю, что это часть сигнатуры функции» - да, соглашение о вызовах является частью сигнатуры. Если соглашение не указано, по умолчанию используется __cdecl (если только компилятор не настроен иначе). Но в 64-битной версии доступно только одно соглашение (и для него нет ключевого слова), поэтому все остальные соглашения (__cdecl, __stdcall и т. д.) просто игнорируются.





На процессорах ARM и x64 __stdcall принимается и игнорируется компилятор; на архитектурах ARM и x64 по соглашению аргументы передается в регистры, когда это возможно, и передаются последующие аргументы в стеке.
Таким образом, __stdcall игнорируется 64-битным компилятором, но имеет смысл только для 32-битного компилятора.
WIL, вероятно, уже предоставляет то, что вы пытаетесь реализовать здесь.