C++20中如何提取std::function的可变参数列表?
问题描述
我正在为一款引擎开发插件,为了后续能适配另一款引擎,尽可能采用模板与元编程技术。目前基于引擎API的函数签名(已去除指针)声明了一批std::function对象,用来注册为引擎信号(比如OnMissionLoad)的回调。
现在需要编写能赋值给这些std::function对象的函数,希望让编译器自动推导参数列表,不用手动写。尝试用typedef提取std::function的参数列表,但现有模板只支持单参数场景,多参数时编译报错:
Error C2794 'type': is not a member of any direct or indirect base class of 'Plugin::std_func_param<std::function<APIResult(WindowID,ButtonID_v1,int32_t,int32_t,BOOL)>>' Error C2938 'Plugin::std_func_param_t' : Failed to specialize alias template
请问在C++20中,如何特化模板以支持可变数量参数,实现通过std::function对象提取其参数列表的功能?
解决方案
在C++20中,你可以通过模板特化结合可变参数模板来提取std::function的参数列表,同时还能获取返回值类型。以下是完整实现:
1. 模板特化实现参数提取
先定义基础模板,再针对std::function的任意签名做特化,支持任意数量的参数:
#include <functional> #include <tuple> namespace Plugin { // 基础模板(未特化版本,用于触发明确的编译错误) template<typename Func> struct std_func_param; // 针对std::function的特化:匹配任意返回值+可变参数列表 template<typename Ret, typename... Args> struct std_func_param<std::function<Ret(Args...)>> { using return_type = Ret; // 提取返回值类型 using args_tuple = std::tuple<Args...>; // 提取参数列表为tuple类型 }; // 别名模板,简化类型提取的写法 template<typename Func> using std_func_param_t = typename std_func_param<Func>::args_tuple; // 可选:提取返回值的别名模板 template<typename Func> using std_func_return_t = typename std_func_param<Func>::return_type; }
2. 使用示例
假设你有这样的std::function声明:
// 引擎API相关类型定义 using APIResult = int; using WindowID = uint32_t; using ButtonID_v1 = uint16_t; // 引擎信号对应的std::function std::function<APIResult(WindowID, ButtonID_v1, int32_t, int32_t, BOOL)> OnButtonClick;
现在可以轻松提取它的参数和返回值类型:
// 提取参数列表为tuple类型 using ButtonClickArgs = Plugin::std_func_param_t<decltype(OnButtonClick)>; // ButtonClickArgs等价于std::tuple<WindowID, ButtonID_v1, int32_t, int32_t, BOOL> // 提取返回值类型 using ButtonClickRet = Plugin::std_func_return_t<decltype(OnButtonClick)>; // ButtonClickRet等价于APIResult
3. 自动推导参数的回调函数实现
如果要编写能自动适配参数的回调,可结合泛型lambda或模板函数,无需手动写参数列表:
// 方式1:泛型lambda(C++14+支持,C++20可配合concept做更严谨的约束) auto buttonCallback = [](auto... args) -> APIResult { // 用结构化绑定直接解析参数(C++17+) auto [windowId, btnId, x, y, isPressed] = std::make_tuple(args...); // 业务逻辑处理... return 0; }; // 直接赋值,编译器自动匹配签名 OnButtonClick = buttonCallback; // 方式2:模板函数,利用参数包展开 template<typename... Args> APIResult buttonCallbackTemplate(Args... args) { // 处理逻辑... return 0; } // 赋值时编译器自动推导参数列表匹配 OnButtonClick = buttonCallbackTemplate;
4. 原错误原因说明
你之前的模板应该只针对单参数场景做了特化(比如std::function<Ret(Arg)>),没有覆盖std::function<Ret(Args...)>这种可变参数的通用情况,导致多参数时编译器找不到对应的特化版本,从而抛出type成员不存在的错误。上面的特化版本用typename... Args可变参数模板,完美支持任意数量的参数。
内容的提问来源于stack exchange,提问作者Jonci
相关产品推荐
相关产品推荐

