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

如何在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 07:35:26