【发布时间】:2020-08-31 10:33:44
【问题描述】:
我有这样的课
/**
Some third party libraries with C interfaces have their own set of functions to allocate and free
heap memory buffers aligned to the specification of the library. This class helps to manage such
buffers in a convenient RAII style
@tparam Type The type of data to hold in the buffer
@tparam SizeType The type used for sizes (in most cases either int or size_t)
@tparam allocFunction A function to call that takes the number of bytes to allocate as argument and returns a pointer
of Type* to the allocated memory
@tparam freeFunction A function to call that takes a void* pointer and frees the previously allocated memory
*/
template <typename Type, typename SizeType, Type* (*allocFunction)(SizeType), void (*freeFunction)(void*)>
class GenericScopedBuffer
这一直很好,直到我现在尝试更新我们仍然构建为 32 Windows 版本的旧产品之一。我们使用一些库,其分配/解除分配函数定义为__stdcall 类型并将它们传递给此类模板,例如
GenericScopedBuffer<char, int, stdcallAllocFunction, stdcallFreeFunction>
导致像C2440: 'specialization': cannot convert from 'void (__stdcall *)(void *)' to 'void (__cdecl *)(void *)'这样的编译器错误
显而易见的原因是 x86 编译器假定像这样声明的函数指针作为指向 __cdecl 函数的指针。现在,由于这个类模板实际上应该与函数指针一起使用任何类型的函数,我想知道是否有办法从传入的函数中扣除调用约定类型。但是,__stdcall 或 __cdecl 不是真正的类型,而更像是提示编译器,对吧?
那么,以跨平台和通用方式启用此功能的好方法是什么?
【问题讨论】:
-
假设您的默认约定是
cdecl,当您编写函数模板时,它会自动添加__cdecl。__cdecl和__stdcall不仅仅是提示,而是构建和调用函数的方式,这就是为什么你不能在cdecl函数和stdcall函数之间转换而不会出现一些堆栈错误。相反,您可以使用简单的typename并使用std::is_function进行检查。 -
是的,我知道
__cdecl和__stdcall之间的根本区别。但是,“您可以使用简单的类型名并使用 std::is_function 进行检查”是什么意思。您能提供一些简短的演示代码供我详细说明吗?
标签: templates c++14 calling-convention