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

C++如何在map中存储带可变多类型参数的成员函数

问题:扩展Calculator类的成员函数映射,支持多参数成员函数

原代码如下:

#include <iostream>
#include <map>
#include <string>
#include <math.h>

using namespace std;

class Calculator{
    private:
        map<string, double (Calculator::*)(double)> mp = {
            {"ABS", &Calculator::abs}};

    public:

    Calculator(){
        cout << (this->*mp["ABS"])(-4.2655) << "\n";
    }

    double abs(double ting){
        return fabs(ting);
    }

};

int main() {
    Calculator calc;
    return 0;
}

当前代码中的map仅能存储带一个double类型参数的成员函数,现希望在该map中添加如sigma()这类带有int startVal、int endVal、string expression多类型参数的成员函数,请问如何基于现有代码结构实现?本人对template不太熟悉,想了解是否需要使用模板及具体用法。


解决方案

原有的map只能存储固定签名的成员函数指针,不同参数列表的成员函数指针属于不同类型,无法直接存入同一个map。要实现需求,需要用类型擦除机制统一存储类型,下面给出两种无需复杂模板的实用方案:

方案一:用std::variant存储不同签名的函数包装器(C++17及以上)

std::variant可以把多种不同类型打包成一种变体类型,我们用它来存放不同签名的std::function,每个成员函数通过lambda包装成对应签名的function存入map。

#include <iostream>
#include <map>
#include <string>
#include <math.h>
#include <functional>
#include <variant>

using namespace std;

class Calculator{
private:
    // 定义变体类型,包含需要支持的两种函数签名
    using FuncVariant = variant<
        function<double(Calculator&, double)>,
        function<double(Calculator&, int, int, string)>
    >;

    map<string, FuncVariant> mp = {
        {"ABS", function<double(Calculator&, double)>([](Calculator& calc, double val) {
            return calc.abs(val);
        })},
        {"SIGMA", function<double(Calculator&, int, int, string)>([](Calculator& calc, int start, int end, string expr) {
            return calc.sigma(start, end, expr);
        })}
    };

public:
    Calculator(){
        // 调用ABS函数:先判断变体类型,再执行
        if (auto* abs_func = get_if<function<double(Calculator&, double)>>(&mp["ABS"])) {
            cout << (*abs_func)(*this, -4.2655) << "\n";
        }

        // 调用SIGMA函数示例
        if (auto* sigma_func = get_if<function<double(Calculator&, int, int, string)>>(&mp["SIGMA"])) {
            cout << (*sigma_func)(*this, 1, 5, "x") << "\n";
        }
    }

    double abs(double ting){
        return fabs(ting);
    }

    double sigma(int startVal, int endVal, string expression){
        // 简单实现:计算start到end的整数累加
        double sum = 0;
        for(int i = startVal; i <= endVal; ++i){
            sum += i;
        }
        return sum;
    }
};

int main() {
    Calculator calc;
    return 0;
}

方案说明

  • 新增FuncVariant类型,枚举所有需要支持的函数签名对应的std::function
  • 每个成员函数用lambda包装,将成员函数调用转换为普通函数调用(传入Calculator引用)
  • 调用时通过get_if判断变体中的实际函数类型,安全执行调用

方案二:用统一签名的std::function+std::any传递参数(更灵活)

定义一个统一的函数签名,用std::any打包任意类型的参数,在lambda中解析参数并调用对应成员函数。这种方式无需每次新增函数都修改变体类型,扩展性更强。

#include <iostream>
#include <map>
#include <string>
#include <math.h>
#include <functional>
#include <any>
#include <stdexcept>

using namespace std;

class Calculator{
private:
    // 统一的通用函数类型:接收Calculator引用和任意参数列表(用vector<any>打包)
    using GenericFunc = function<double(Calculator&, const vector<any>&)>;

    map<string, GenericFunc> mp = {
        {"ABS", [](Calculator& calc, const vector<any>& args) {
            if(args.size() != 1) throw invalid_argument("ABS需要1个double类型参数");
            return calc.abs(any_cast<double>(args[0]));
        }},
        {"SIGMA", [](Calculator& calc, const vector<any>& args) {
            if(args.size() != 3) throw invalid_argument("SIGMA需要3个参数:int, int, string");
            return calc.sigma(
                any_cast<int>(args[0]),
                any_cast<int>(args[1]),
                any_cast<string>(args[2])
            );
        }}
    };

public:
    Calculator(){
        // 调用ABS
        try {
            cout << mp["ABS"](*this, {-4.2655}) << "\n";
        } catch(const exception& e){
            cerr << "调用ABS出错:" << e.what() << endl;
        }

        // 调用SIGMA
        try {
            cout << mp["SIGMA"](*this, {1, 5, "x"}) << "\n";
        } catch(const exception& e){
            cerr << "调用SIGMA出错:" << e.what() << endl;
        }
    }

    double abs(double ting){
        return fabs(ting);
    }

    double sigma(int startVal, int endVal, string expression){
        double sum = 0;
        for(int i = startVal; i <= endVal; ++i){
            sum += i;
        }
        return sum;
    }
};

int main() {
    Calculator calc;
    return 0;
}

方案说明

  • 用GenericFunc统一所有函数的签名,参数中的vector<any>可以容纳任意数量、任意类型的参数
  • 每个lambda负责校验参数数量和类型,通过any_cast将std::any转换为具体类型后调用成员函数
  • 加入异常处理,避免参数错误导致程序崩溃

关于模板的说明

上面两种方案都不需要复杂的模板语法,完全满足你的需求。如果以后需要实现更通用的参数打包逻辑,才需要用到可变参数模板,但当前场景下,上述两种方案足够简单实用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 04:07:03