You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何移除函数指针或引用的__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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 18:16:07