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

如何在C++容器中存储不同参数的类成员函数指针

解决方法

你想直接在/*FUNCTION ARGS*/位置用可变模板适配不同成员函数的签名是行不通的——因为std::unordered_map要求所有元素的value类型必须完全一致,而不同签名的std::function属于不同类型,没法直接放入同一个容器。

要实现存储不同签名成员函数指针的容器,有两种常用可行方案:

方案1:用std::variant封装不同的std::function类型

先定义每个成员函数对应的std::function类型,再用std::variant把它们打包成统一类型,作为容器的value类型。这种方式类型安全,是推荐的做法。

示例代码:

#include <unordered_map>
#include <functional>
#include <variant>
#include <string>

class MyClass
{
public:
    void funcOne(int a, float b) {}
    void funcTwo(std::string) {}
    void funcThree() {}
};

// 定义每个成员函数对应的std::function类型(第一个参数为类实例引用)
using Func1 = std::function<void(MyClass&, int, float)>;
using Func2 = std::function<void(MyClass&, std::string)>;
using Func3 = std::function<void(MyClass&)>;

// 用variant统一所有函数类型
using AnyMemberFunc = std::variant<Func1, Func2, Func3>;

// 最终容器定义
std::unordered_map<int, AnyMemberFunc> myMap;

// 使用示例
int main() {
    // 将成员函数包装为lambda存入容器
    myMap[1] = [](MyClass& obj, int a, float b) { obj.funcOne(a, b); };
    myMap[2] = [](MyClass& obj, std::string s) { obj.funcTwo(std::move(s)); };
    myMap[3] = [](MyClass& obj) { obj.funcThree(); };

    MyClass obj;
    // 调用时用std::visit匹配对应函数类型
    std::visit([&obj](auto&& func) {
        using FuncType = std::decay_t<decltype(func)>;
        if constexpr (std::is_same_v<FuncType, Func1>) {
            func(obj, 10, 3.14f);
        } else if constexpr (std::is_same_v<FuncType, Func2>) {
            func(obj, "test");
        } else if constexpr (std::is_same_v<FuncType, Func3>) {
            func(obj);
        }
    }, myMap[1]);
}

方案2:统一适配为带std::any参数的函数(灵活性高但类型不安全)

如果不想预先枚举所有函数类型,可以把所有成员函数适配成接收MyClass实例和任意数量std::any参数的std::function,但调用时需要手动校验并转换参数类型,存在类型错误风险。

示例代码:

#include <unordered_map>
#include <functional>
#include <any>
#include <string>

class MyClass
{
public:
    void funcOne(int a, float b) {}
    void funcTwo(std::string) {}
    void funcThree() {}
};

// 统一的函数类型
using UnifiedFunc = std::function<void(MyClass&, const std::vector<std::any>&)>;

// 容器定义
std::unordered_map<int, UnifiedFunc> myMap;

// 使用示例
int main() {
    myMap[1] = [](MyClass& obj, const std::vector<std::any>& args) {
        // 手动校验参数数量和类型
        if (args.size() != 2) return;
        int a = std::any_cast<int>(args[0]);
        float b = std::any_cast<float>(args[1]);
        obj.funcOne(a, b);
    };

    myMap[2] = [](MyClass& obj, const std::vector<std::any>& args) {
        if (args.size() != 1) return;
        std::string s = std::any_cast<std::string>(args[0]);
        obj.funcTwo(std::move(s));
    };

    myMap[3] = [](MyClass& obj, const std::vector<std::any>&) {
        obj.funcThree();
    };

    MyClass obj;
    // 调用时传入参数的any数组
    myMap[1](obj, {10, 3.14f});
}

关键说明

成员函数必须依赖类实例才能调用,所以不管哪种方案,std::function的签名里都需要包含MyClass的实例(引用或指针)作为第一个参数——这是成员函数和普通函数的核心区别。

内容的提问来源于stack exchange,提问作者cpp_hex

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 22:57:37