c++ - 如何知道 Qt 项目是否正在使用调用约定?

标签 c++ templates calling-convention

你知道,当你定义一个函数时,你可以同时定义它的调用约定,就像这样:

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/

相关文章:

c++ - 是否可以将派生类对象视为同类型的基类? <noobieQ/>

c++ - 字符 *(64 位(Windows 7))

c++ - 低功耗处理器的快速搜索-插入-删除算法

c++ - 处理方法结果的可变参数模板

templates - 在 Angular 2 的 html 模板中引用服务是一种好习惯吗?

compiler-construction - x64 上的调用约定

c++ - HttpAddRequestHeaders 添加的 header 和 HttpSendRequest 发送的 header 有什么区别

java - 扩展 Axis 代码生成模块

visual-c++ - 这个接口(interface)二进制文件在 MSVC 和 mingw 之间是否兼容?

c - 为什么 gcc 使用 movl 而不是 push 来传递函数参数?