你知道,当你定义一个函数时,你可以同时定义它的调用约定,就像这样:
int __stdcall foo(int) { return 1; };
int __cdecl bar(int) { return 1; };
而如果你想使用这个函数来推导模板参数,你必须处理调用约定,例如:
template<typename T> void tmpl_func( T( __stdcall f )(T) ) { other_func<T>(); };
使用此模板,您只能使用“foo”作为参数。如果使用“bar”,则无法编译。
tmpl_func(foo); // ok
tmpl_func(bar); // err
因此,如果您有一个使用 __cdecl 的函数,则必须使用两种调用约定来定义模板函数,如下所示:
template<typename T> void tmpl_func( T( __stdcall f )(T) ) { other_func<T>(); };
template<typename T> void tmpl_func( T( __cdecl f )(T) ) { other_func<T>(); };
而foo实例化了__stdcall版本,bar实例化了__cdecl版本,没有重定义。
总的来说,这很好用,但最近我遇到了一个问题:
在 Qt 项目中,当我按照上面所说的方式定义模板函数时,编译器说:__cdecl 模板函数已经定义。
如果你只在__stdcall 版本中定义tmpl_func,它也可以使用bar 作为它的参数。
这是否意味着我编写的所有调用约定标识符都不起作用,并且所有函数都以__cdecl 方式调用?
为什么以及如何知道这种情况是否会发生?我可以使用宏或编译选项检查它吗?
抱歉我的英语不好,我希望我已经说清楚了,但这确实困扰了我一段时间。
最佳答案
You know, when you define a function, you can define it's calling convention at the same time
这是错误的。您描述的是 C++ 的(特定于供应商的)扩展。例如,在我的 GCC 上Linux 上的编译器,它可能无法工作。
In a Qt project,
根本不要使用任何显式 __stdcall
或 __cdecl
Qt 代码中的注释。
(在您的 Qt 代码中使用它是搬起石头砸自己的脚:它伤得很厉害;坚持 Qt5 项目的标准 C++11 代码)
如果您需要调用一些外部 奇怪的函数(使用奇怪且显式 调用约定)写一些extern "C"
(或一些 static inline
一个,如果它很短)包装函数这样做(并且您的包装函数具有通常的签名,没有显式调用约定注释)。
实际上,当编写一个 Qt 项目时,你编译它时会出现所有警告和调试信息(如果使用 GCC,那么 g++ -Wall -g
),你会用你的 gdb
调试它。调试器,然后您可以对其进行优化(例如使用 g++ -Wall -g -O2
进行编译)-例如对于基准测试和生产代码——你相信编译器可以很好地优化,内联许多函数调用,并选择足够好的调用约定。不要乱用 Qt 代码中的调用约定。
(隐含地,您是在询问 __stdcall
或 __cdecl
是否以及如何改变 C++ 的类型系统;C++ 类型已经足够复杂,您不想要更多的困惑)
关于c++ - 如何知道 Qt 项目是否正在使用调用约定?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42312659/