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

如何移除Wrapper间接层,实现C++模板参数包的直接转换?

移除Wrapper间接层的C++模板技巧

问题背景

现有代码通过Wrapper结构体间接实现了编译期绑定函数指针并转换参数的逻辑,核心代码如下:

现有可运行代码

template <typename ...Types>
struct Wrapper
{
    template <void (*F)(typename Types::ParameterType...)>
    static void toNativeFunction(Stuff stuff)
    {
        auto arguments = toConvertedArguments<Types...>(stuff);
    
        std::apply(F, arguments);
    }
};

// toConvertedArguments 声明
template<typename... Types>
using converted_tuple = std::tuple<typename Converter<Types>::ReturnType...>;

template<typename... Types>
converted_tuple<Types...> toConvertedArguments(Stuff stuff);

// 调用示例
void implementation(int);

template<typename T>
class SomeClass
{
    using ParameterType = T;
};

// 使用Wrapper调用
{
    Wrapper<SomeClass<int>>::toNativeFunction<&implementation>(stuff);
}

Wrapper的存在仅仅是为了绕开C++模板的语法限制:参数包Types...不能直接放在非类型模板参数(函数指针F)之前,而交换顺序后编译器又无法推导Types...。我们的目标是移除这个间接层,实现更直观的调用方式。

解决方案

方法1:C++20 auto非类型模板参数(最简洁)

利用C++20引入的auto非类型模板参数,让编译器自动推导函数指针的类型,再通过辅助模板反向映射出Types...:

// 辅助模板:从函数指针类型提取参数,映射为SomeClass<T>的列表
template<typename Func>
struct ExtractTypes;

template<typename... Args>
struct ExtractTypes<void(*)(Args...)>
{
    using type = std::tuple<SomeClass<Args>...>;
};

// 目标函数模板:auto推导函数指针,requires约束确保Types匹配
template<auto F, typename... Types>
requires (std::same_as<std::tuple<Types...>, typename ExtractTypes<decltype(F)>::type>)
static void toNativeFunction(Stuff stuff)
{
    auto arguments = toConvertedArguments<Types...>(stuff);
    std::apply(F, arguments);
}

// 调用方式(无需Wrapper)
{
    toNativeFunction<&implementation>(stuff);
}

编译器会自动推导函数指针&implementation的类型,通过ExtractTypes得到对应的SomeClass<int>,再通过requires约束匹配Types...,完全消除了Wrapper的间接层。

方法2:C++17及以上的模板特化推导

如果无法使用C++20,可以通过辅助结构体的模板特化来推导Types...:

// 辅助结构体:匹配函数指针和对应的SomeClass列表
template<void(*F)(typename Types::ParameterType...), typename... Types>
struct Helper;

// 特化版本:将函数参数Args...映射为SomeClass<Args>
template<void(*F)(Args...), typename... Args>
struct Helper<F, SomeClass<Args>...>
{
    static void call(Stuff stuff)
    {
        auto arguments = toConvertedArguments<SomeClass<Args>...>(stuff);
        std::apply(F, arguments);
    }
};

// 对外的函数模板:仅接受函数指针参数,委托给Helper
template<void(*F)>
static void toNativeFunction(Stuff stuff)
{
    Helper<F>::call(stuff);
}

// 调用方式(无需Wrapper)
{
    toNativeFunction<&implementation>(stuff);
}

这里Helper的特化会自动匹配函数指针F的参数类型Args...,对应到SomeClass<Args>,从而完成Types...的推导,同样可以移除Wrapper。

总结

以上两种方法都能直接实现目标逻辑,无需额外的Wrapper结构体。其中C20的auto非类型模板参数写法最简洁直观,是首选方案;如果需要兼容更早的C标准,模板特化推导的方式同样可行。

内容的提问来源于stack exchange,提问作者Francisco Ryan Tolmasky I

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 00:07:44