如何移除函数指针或引用的__attribute__并适配现有模板?
问题:如何移除函数签名中的
__attribute__((...))调用约定,或让现有模板无需特化即可兼容? 测试代码与现象
用户测试代码如下:
#include <utility> #include <iostream> int main() { using std_type = std::remove_reference<void (__attribute__((stdcall)) &)(int) noexcept>::type; using cdecl_type = std::remove_reference<void (__attribute__((cdecl)) &)(int) noexcept>::type; using type = std::remove_reference<void (&)(int) noexcept>::type; std::cout<<typeid(std_type).name()<<"\n"; std::cout<<typeid(cdecl_type).name()<<"\n"; std::cout<<typeid(type).name()<<"\n"; }
运行输出:
U7stdcallDoFviE U5cdeclDoFviE U5cdeclDoFviE
通过std::is_same<std_type, cdecl_type>::value比较时返回false,说明带不同调用约定的函数类型被视为不同类型。
现有模板代码
用户现有用于提取函数签名和参数类型的模板如下:
提取类成员函数签名的模板
template<typename T> struct remove_class {}; template<typename C, typename R, typename... A> struct remove_class<R(C::*)(A...)> { using type = R(A...); }; template <typename C, typename R, typename... A> struct remove_class<R(C::*)(A...) const> { using type = R(A...); }; template<typename C, typename R, typename... A> struct remove_class<R(C::*)(A...) volatile> { using type = R(A...); }; template<typename C, typename R, typename... A> struct remove_class<R(C::*)(A...) noexcept> { using type = R(A...); }; template<typename C, typename R, typename... A> struct remove_class<R(C::*)(A...) const volatile> { using type = R(A...); }; template<typename C, typename R, typename... A> struct remove_class<R(C::*)(A...) const noexcept> { using type = R(A...); }; template<typename C, typename R, typename... A> struct remove_class<R(C::*)(A...) volatile noexcept> { using type = R(A...); }; template<typename C, typename R, typename... A> struct remove_class<R(C::*)(A...) const volatile noexcept> { using type = R(A...); }; template<typename T> struct function_signature { using type = typename remove_class<decltype(&std::remove_reference<T>::type::operator())>::type; }; template<typename R, typename... A> struct function_signature<R(A...)> { using type = R(A...); };
提取函数参数类型的模板
template<typename T> struct function_arguments_type { using type = typename function_arguments_type<typename function_signature<T>::type>::type; }; template<typename R, typename... A> struct function_arguments_type<R(A...)> { using type = typename std::tuple<A...>; };
核心需求
用户希望移除函数签名中的__attribute__((...))调用约定属性,让上述现有模板无需为__stdcall等调用约定编写额外特化,就能正常提取函数的返回类型和参数类型。
解决方案:通过模板特化剥离调用约定属性
针对GCC/Clang的__attribute__调用约定扩展,可以编写通用模板剥离函数类型中的调用约定属性,将其转换为普通函数类型,从而让现有模板直接兼容。
1. 编写remove_call_convention模板
该模板负责匹配带调用约定的函数类型,并返回对应的普通函数类型:
#include <type_traits> // 基础模板:默认返回原类型 template<typename T> struct remove_call_convention { using type = T; }; // 处理带stdcall属性的 noexcept 函数 template<typename R, typename... Args> struct remove_call_convention<R(__attribute__((stdcall)))(Args...) noexcept> { using type = R(Args...) noexcept; }; // 处理带stdcall属性的普通函数 template<typename R, typename... Args> struct remove_call_convention<R(__attribute__((stdcall)))(Args...)> { using type = R(Args...); }; // 处理带cdecl属性的 noexcept 函数 template<typename R, typename... Args> struct remove_call_convention<R(__attribute__((cdecl)))(Args...) noexcept> { using type = R(Args...) noexcept; }; // 处理带cdecl属性的普通函数 template<typename R, typename... Args> struct remove_call_convention<R(__attribute__((cdecl)))(Args...)> { using type = R(Args...); }; // 可扩展支持其他调用约定,比如fastcall等 template<typename R, typename... Args> struct remove_call_convention<R(__attribute__((fastcall)))(Args...) noexcept> { using type = R(Args...) noexcept; }; template<typename R, typename... Args> struct remove_call_convention<R(__attribute__((fastcall)))(Args...)> { using type = R(Args...); }; // 辅助别名,简化使用 template<typename T> using remove_call_convention_t = typename remove_call_convention<T>::type;
2. 修改现有function_signature模板
在function_signature中引入remove_call_convention,确保提取的签名是剥离了调用约定的普通函数类型:
template<typename T> struct function_signature { // 先提取类成员函数的原始签名,再剥离调用约定 using raw_signature = typename remove_class<decltype(&std::remove_reference<T>::type::operator())>::type; using type = remove_call_convention_t<raw_signature>; }; // 针对普通函数类型的特化,同样剥离调用约定 template<typename R, typename... A> struct function_signature<R(A...)> { using type = remove_call_convention_t<R(A...)>; }; // 针对函数指针类型的特化(如果需要处理函数指针) template<typename R, typename... A> struct function_signature<R(__attribute__((stdcall))(*)(A...) noexcept)> { using type = remove_call_convention_t<R(A...) noexcept>; }; template<typename R, typename... A> struct function_signature<R(__attribute__((stdcall))(*)(A...))> { using type = remove_call_convention_t<R(A...)>; };
原理说明
通过模板特化精准匹配带有__attribute__((stdcall))/__attribute__((cdecl))等属性的函数类型,将其映射为不带调用约定的等价函数类型。这样后续的function_arguments_type模板就能直接基于普通函数类型提取参数元组,无需为每个调用约定单独编写特化。
内容的提问来源于stack exchange,提问作者Brandon
相关产品推荐
相关产品推荐

