如何存储成员函数并实现可变参数模板函数以使用特定参数调用存储的函数?
假设我已将一些类的成员函数存储到一个由标识符索引的容器中。
我想创建一个可变参数模板函数
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;
}
奖励: 如果特定的执行函数具有返回类型,如何使
processArgs
返回执行函数的结果?例如 processArgs(1, 2.0, 4.0, 6.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);
}