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

如何存储类成员函数并实现可变参数模板函数调用及返回结果?

问题描述

需要实现以下功能:

  • 将多个类的成员函数存入以标识符为索引的容器中
  • 实现可变参数模板函数processArgs,完成:
    1. 接收标识符和一组参数
    2. 通过标识符在容器中找到对应函数
    3. 用提供的参数调用该函数
    4. 支持调用const成员函数
  • 额外需求:让processArgs返回被调用函数的执行结果

示例代码如下:

#include <iostream>
#include <unordered_map>

class MyClass {
public:
    void someFunc(const char* str, int a, double b) {
        std::cout << str << " " << a << " " << b << std::endl;
    }

    float magnitude(double x, double y, double z) {
        return sqrt(x*x+y*y+z*z);
    }

    std::string toStr(float x) {
        return std::to_string(x);
    }
};

using fnId = int;

std::unordered_map<fnId, Ret (Classes::*)(Args...)> functions; // This is going to be filled with functions

template<typename... Args>
void processArgs(int fnId, Args... args)
{
    // This function will retrieve a function by fnId, and forward args in specific order/type to that specific function, for that specific object
    // so it will be like obj->someFunc(args...);
}

int main()
{
    MyClass obj;
    
    // Assuming the container is filled with functions
    functions[0] = &MyClass::someFunc;
    functions[1] = &MyClass::magnitude;
    functions[2] = &MyClass::toStr;
    
    // This is how i execute 
    processArgs(0, "text", 30, 3.34);
    processArgs(1, 2.0, 4.0, 6.0);
    processArgs(2, 3.14159);
    
    return 0;
}
解决方案

1. 容器类型改造

不同成员函数的返回值、参数、所属类存在差异,直接存储成员函数指针无法兼容。改用std::unordered_map<fnId, std::any>作为容器,用std::any存储不同签名的std::function对象,实现统一存储。

2. 成员函数注册方式

注册时通过std::bind绑定对象实例和成员函数,将成员函数转换为可直接调用的std::function,再存入容器。普通成员函数和const成员函数都可以用这种方式处理:

// 注册普通成员函数
functions[0] = std::function<void(const char*, int, double)>(
    std::bind(&MyClass::someFunc, &obj, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)
);

// 注册const成员函数
functions[3] = std::function<int()>(
    std::bind(&ConstClass::getValue, &constObj)
);

3. 实现processArgs函数

通过模板重载分别处理有返回值和无返回值的情况,利用std::any_cast将容器中的std::any转换为对应类型的std::function,再转发参数调用并返回结果:

template<typename Ret, typename... Args>
Ret processArgs(fnId id, Args&&... args) {
    auto& func_any = functions.at(id);
    auto func = std::any_cast<std::function<Ret(Args...)>>(&func_any);
    if (!func) {
        throw std::runtime_error("Function type mismatch");
    }
    return (*func)(std::forward<Args>(args)...);
}

template<typename... Args>
void processArgs(fnId id, Args&&... args) {
    auto& func_any = functions.at(id);
    auto func = std::any_cast<std::function<void(Args...)>>(&func_any);
    if (!func) {
        throw std::runtime_error("Function type mismatch");
    }
    (*func)(std::forward<Args>(args)...);
}

完整可运行代码

#include <iostream>
#include <unordered_map>
#include <functional>
#include <any>
#include <cmath>
#include <stdexcept>

class MyClass {
public:
    void someFunc(const char* str, int a, double b) {
        std::cout << str << " " << a << " " << b << std::endl;
    }

    float magnitude(double x, double y, double z) const {
        return sqrt(x*x + y*y + z*z);
    }

    std::string toStr(float x) {
        return std::to_string(x);
    }
};

class ConstClass {
public:
    int getValue() const {
        return 42;
    }
};

using fnId = int;
std::unordered_map<fnId, std::any> functions;

template<typename Ret, typename... Args>
Ret processArgs(fnId id, Args&&... args) {
    auto& func_any = functions.at(id);
    auto func = std::any_cast<std::function<Ret(Args...)>>(&func_any);
    if (!func) {
        throw std::runtime_error("Function type mismatch");
    }
    return (*func)(std::forward<Args>(args)...);
}

template<typename... Args>
void processArgs(fnId id, Args&&... args) {
    auto& func_any = functions.at(id);
    auto func = std::any_cast<std::function<void(Args...)>>(&func_any);
    if (!func) {
        throw std::runtime_error("Function type mismatch");
    }
    (*func)(std::forward<Args>(args)...);
}

int main() {
    MyClass obj;
    ConstClass constObj;

    // 注册各类成员函数
    functions[0] = std::function<void(const char*, int, double)>(
        std::bind(&MyClass::someFunc, &obj, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)
    );

    functions[1] = std::function<float(double, double, double)>(
        std::bind(&MyClass::magnitude, &obj, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)
    );

    functions[2] = std::function<std::string(float)>(
        std::bind(&MyClass::toStr, &obj, std::placeholders::_1)
    );

    functions[3] = std::function<int()>(
        std::bind(&ConstClass::getValue, &constObj)
    );

    // 调用测试
    processArgs(0, "text", 30, 3.34);
    
    float mag = processArgs<float>(1, 2.0, 4.0, 6.0);
    std::cout << "Magnitude: " << mag << std::endl;
    
    std::string str = processArgs<std::string>(2, 3.14159f);
    std::cout << "String: " << str << std::endl;
    
    int val = processArgs<int>(3);
    std::cout << "Const value: " << val << std::endl;

    return 0;
}

关键说明

  • std::any作为容器值类型,兼容不同签名的函数对象
  • std::bind完成成员函数与对象实例的绑定,消除成员函数的隐式this参数
  • 模板化的processArgs支持参数转发,保证调用效率
  • 重载版本分别处理无返回值和有返回值的函数调用,同时兼容const成员函数

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 06:54:52