实现可变参数模板函数以通过标识符调用存储的类成员函数?

问题描述 投票:0回答:1

如何存储成员函数并实现可变参数模板函数以使用特定参数调用存储的函数?

假设我已将一些类的成员函数存储到一个由标识符索引的容器中。

我想创建一个可变参数模板函数

processArgs

  1. 采用标识符和一组参数。
  2. 使用标识符在地图中查找相应的功能。
  3. 使用提供的参数调用函数。
  4. 存储的函数可能是const

问题的概要如下:

#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;
}

奖励: 如果特定的执行函数具有返回类型,如何使

processArgs
返回执行函数的结果?例如
processArgs(1, 2.0, 4.0, 6.0)
应返回计算值。

c++ variadic-templates type-erasure
1个回答
0
投票

如果特定执行函数具有返回类型,如何使 processArgs 返回执行函数的结果?

您可以使用

std::tuple
来实现您想要的效果,如下所示。请注意使用
decltype
使代码更具可读性。另外,对于 c++17,我们可以使用
std::invoke
使其更具可读性。

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 std::sqrt(x*x+y*y+z*z);
    }

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

std::tuple<decltype(&MyClass::someFunc), decltype(&MyClass::magnitude), decltype(&MyClass::toStr)> functions 
                     = { &MyClass::someFunc, &MyClass::magnitude, &MyClass::toStr}; // This is going to be filled with functions

template<int fnId, typename... Args>
auto processArgs( const Args&... args)
{
    using std::get;
    MyClass obj;
    //with C++17 we use std::invoke 
    return std::invoke(get<fnId>(functions), obj, args...);
}

int main()
{  
    
    processArgs<0>( "text", 30, 3.34);
    processArgs<1>( 2.0, 4.0, 6.0);
    processArgs<2>( 3.14159);

}
© www.soinside.com 2019 - 2024. All rights reserved.