如何在STL容器std::map中存储不同签名的回调函数指针?
存储不同签名回调到std::map的解决方案
要在std::map中存储不同签名、不同返回值的回调函数,核心是用**std::variant**作为map的value类型——它能安全容纳多种不同类型的函数对象,同时保留类型信息,方便后续正确调用。
1. 定义可容纳所有回调类型的variant
先把你需要的所有回调签名转换成对应的std::function类型,再用std::variant包裹:
#include <variant> #include <functional> #include <map> #include <string> // 提前声明GStreamer相关类型(若已包含头文件可跳过) typedef struct _GstPad GstPad; typedef struct _GstPadProbeInfo GstPadProbeInfo; typedef struct _GstElement GstElement; typedef enum { GST_PAD_PROBE_OK } GstPadProbeReturn; typedef enum { GST_FLOW_OK } GstFlowReturn; typedef void* gpointer; // 定义能容纳所有回调的variant类型 using CallbackVariant = std::variant< std::function<GstPadProbeReturn(GstPad*, GstPadProbeInfo*, gpointer)>, std::function<GstFlowReturn(GstPad*, GstPadProbeInfo*, gpointer)>, std::function<void(GstElement*, GstPad*, gpointer)> >; // 声明你的回调函数 GstPadProbeReturn callback_1(GstPad *pad, GstPadProbeInfo *info, gpointer u_data); GstFlowReturn callback_2(GstPad *pad, GstPadProbeInfo *info, gpointer sharedPtr); void callback_3(GstElement *element, GstPad *pad, gpointer u_data);
2. 填充std::map
直接用emplace将回调存入map,std::variant会自动匹配对应的std::function类型:
std::map<std::string, CallbackVariant> cb_map; // 存入回调 cb_map.emplace("func1", callback_1); cb_map.emplace("func2", callback_2); cb_map.emplace("func3", callback_3);
3. 取出并调用回调
根据不同使用场景,有两种安全的调用方式:
方式一:针对特定类型提取(比如给gst_pad_add_probe用)
如果需要将回调传给gst_pad_add_probe这类要求特定签名的函数,用std::get_if提取对应类型的std::function,避免类型不匹配的异常:
// 示例:取出func1并传给gst_pad_add_probe auto it = cb_map.find("func1"); if (it != cb_map.end()) { // 尝试获取GstPadProbeReturn类型的回调 auto* target_cb = std::get_if< std::function<GstPadProbeReturn(GstPad*, GstPadProbeInfo*, gpointer)> >(&it->second); if (target_cb != nullptr) { // 直接传入gst_pad_add_probe,签名完全匹配 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BLOCK, *target_cb, u_data, nullptr); } }
方式二:通用调用(用std::visit统一处理)
如果需要直接调用回调,可以写一个访问器结构体,用std::visit自动匹配对应的回调类型并执行:
// 定义访问器,处理每种回调的调用逻辑 struct CallbackInvoker { // 处理func1类型的回调 void operator()(const std::function<GstPadProbeReturn(GstPad*, GstPadProbeInfo*, gpointer)>& cb, GstPad* pad, GstPadProbeInfo* info, gpointer data) const { cb(pad, info, data); } // 处理func2类型的回调 void operator()(const std::function<GstFlowReturn(GstPad*, GstPadProbeInfo*, gpointer)>& cb, GstPad* pad, GstPadProbeInfo* info, gpointer data) const { cb(pad, info, data); } // 处理func3类型的回调 void operator()(const std::function<void(GstElement*, GstPad*, gpointer)>& cb, GstElement* elem, GstPad* pad, gpointer data) const { cb(elem, pad, data); } // 处理不匹配的情况(可选:抛出异常或打日志) template<typename T> void operator()(const T&, ...) const { throw std::bad_variant_access(); } }; // 调用示例 // 调用func1 std::visit(CallbackInvoker{}, cb_map["func1"], pad, info, u_data); // 调用func3 std::visit(CallbackInvoker{}, cb_map["func3"], element, pad, u_data);
为什么之前的方法失败?
你之前用std::function<void()>作为map的value类型,但你的回调都是带参数、有返回值的,类型完全不匹配,自然无法存入。而std::variant允许你在同一个容器中存储多种不同的std::function,完美解决类型不兼容的问题。
内容的提问来源于stack exchange,提问作者Grudy
相关产品推荐
相关产品推荐

