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

如何实现可存储任意返回类型、任意参数数量及类型函数指针的std::map?(附Boost.Variant尝试代码及问题)

解决存储任意签名函数指针到std::map的问题

嘿,我来帮你搞定这个问题!先看看你当前代码里的几个关键问题:

  • typedef不能重复定义(重载):C++里不允许同名的typedef多次定义,你第二个typedef MultiType(*FnPtr)(MultiType, MultiType, MultiType);直接覆盖了第一个,导致str函数(签名是MultiType(std::string))和FnPtr类型不匹配,根本没法塞进map里。
  • std::map的value类型必须统一:同一个map里的所有value必须是同一种类型,你没法直接把不同签名的函数指针混存进去。

下面给你两种基于Boost库的可行方案,都是贴合你的需求来做的:


方案一:用boost::variant存储不同签名的函数指针

我们可以把各种不同类型的函数指针塞进boost::variant这个“万能容器”里,让map的value类型变成这个variant,这样就能存多种签名的函数了。

#include <boost/variant.hpp>
#include <map>
#include <iostream>
#include <string>

using namespace boost;
typedef boost::variant<int, float, double, std::string> MultiType;

// 先给不同签名的函数指针分别定义类型
typedef MultiType (*Fn2Args)(MultiType, MultiType);
typedef MultiType (*Fn1StrArg)(std::string);

// 用variant把这些类型统一起来
typedef boost::variant<Fn2Args, Fn1StrArg> AnyFnPtr;

// 你的原函数完全不用改
MultiType add(MultiType i, MultiType j) { return get<int>(i) + get<int>(j);}
MultiType sub(MultiType i, MultiType j) { return get<int>(i) - get<int>(j);}
MultiType str(std::string s) { return s; }

int main() {
    std::map<std::string, AnyFnPtr> myMap;
    myMap["add"] = add;
    myMap["sub"] = sub;
    myMap["str"] = str;

    // 调用的时候得先判断variant里的实际函数类型
    std::string op("add");
    // 用boost::get尝试获取对应的函数指针
    if (Fn2Args* fn = boost::get<Fn2Args>(&myMap[op])) {
        int res = get<int>((*fn)(2, 3));
        std::cout << res << std::endl;
    }

    // 调用str函数的例子
    op = "str";
    if (Fn1StrArg* fn = boost::get<Fn1StrArg>(&myMap[op])) {
        std::string res = get<std::string>((*fn)("hello there"));
        std::cout << res << std::endl;
    }
}

这个方案的好处是不用修改你原来的函数,但调用的时候需要做类型判断,稍微有点麻烦。


方案二:用boost::function统一封装所有函数

如果想让调用逻辑更简洁,可以把所有函数都封装成接受MultiType向量、返回MultiType的统一类型,用boost::function来做这个包装。

#include <boost/variant.hpp>
#include <boost/function.hpp>
#include <map>
#include <iostream>
#include <string>
#include <vector>
#include <stdexcept>

using namespace boost;
typedef boost::variant<int, float, double, std::string> MultiType;

// 定义统一的函数包装类型
typedef boost::function<MultiType(const std::vector<MultiType>&)> AnyFn;

// 给每个原函数写个适配器,把参数转换成向量形式
MultiType add_adapter(const std::vector<MultiType>& args) {
    if (args.size() != 2) throw std::invalid_argument("add需要2个参数");
    return get<int>(args[0]) + get<int>(args[1]);
}

MultiType sub_adapter(const std::vector<MultiType>& args) {
    if (args.size() != 2) throw std::invalid_argument("sub需要2个参数");
    return get<int>(args[0]) - get<int>(args[1]);
}

MultiType str_adapter(const std::vector<MultiType>& args) {
    if (args.size() != 1) throw std::invalid_argument("str需要1个参数");
    return get<std::string>(args[0]);
}

int main() {
    std::map<std::string, AnyFn> myMap;
    myMap["add"] = add_adapter;
    myMap["sub"] = sub_adapter;
    myMap["str"] = str_adapter;

    // 调用add,直接传参数向量就行
    std::string op("add");
    int res = get<int>(myMap[op]({2, 3}));
    std::cout << res << std::endl;

    // 调用str
    op = "str";
    std::string str_res = get<std::string>(myMap[op]({"hello stackoverflow"}));
    std::cout << str_res << std::endl;
}

这个方案调用的时候特别统一,不用做类型判断,但需要给每个原函数写个适配器。如果你的函数很多,可以考虑用模板来简化适配器的编写,避免重复代码。


额外提一句:如果你用的是C++11及以上版本,也可以用标准库的std::function和std::variant替代Boost的对应组件,用法几乎一模一样。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.27 16:24:07