根据字符串参数调用函数

call functions depending on a string Parameter

本文关键字:调用 函数 参数 字符串      更新时间:2023-10-16

我试图找到一种根据一个字符串参数调用函数的方法。

枚举Int 对于参数类型也可以。也许还有更多的东西?有没有办法这样做:

myFunction(string functionParameter, int value){
this->functionParameter(value);}

最好的方法是什么?我知道有一些类似的问题,但我没有找到真正适合我问题的答案。

只需使用映射从字符串映射到函数:

void f1()
{
    std::cout << "f1!" << std::endl;
}
void f2()
{
    std::cout << "f2!" << std::endl;
}
void f3()
{
    std::cout << "f3!" << std::endl;
}
int main()
{
    std::unordered_map<std::string,std::function<void()>> map;
    map["f1"] = f1;
    map["f2"] = f2;
    map["f3"] = f3;
    map["f1"]();
    map["f2"]();
    map["f3"]();
}

这输出:

F1!
f2!
f3!

C++没有

直接支持使用该名称调用函数。您需要以某种方式创建映射。最简单的方法可能是创建合适的std::function<...>类型的地图:

void f(int);
void g(int);
typedef std::function<void(int)> Function;
std:: map<std::string, Function> functions;
// ...
functions["f"] = f;
functions["g"] = g;
void call(std::string const& name, int x) {
    auto it = functions.find(name);
    if (it->second != functions.end()) {
        it->second(x);
    }
    else {
        // deal with unknown functions
    }
}

可以将字符串映射到函数指针。尝试这样的事情:

#include <iostream>
#include <string>
#include <functional>
#include <map>
class X;
template<class X>
class handler_factory;
template<>
class handler_factory<X>
{
private:
    using HandlerType = void (X::*)(int);
public:
    handler_factory();
    HandlerType get(const std::string& name) const
    {
        if (handlers.find(name) == handlers.end())
            return nullptr;
        else
            return (*handlers.find(name)).second;
    }
private:
    std::map<std::string, HandlerType> handlers;
};
class X
{
public:
    friend class handler_factory<X>;
private:
    void f(int);
    void h(int);
};
handler_factory<X>::handler_factory()
{
    handlers["f"] = &X::f;
    handlers["h"] = &X::h;
}
void X::f(int) { std::cout << "X::f();"; }
void X::h(int) { std::cout << "X::h();"; }

您的类(在此示例中为 X )可以具有如下所示的函数dispatch_method

template<typename... Args>
void dispatch_method(const std::string& name, Args&&... args)
{
    if (find_handler(name))
        (this->*find_handler(name))(std::forward<Args>(args...));
}

其中find_handler是帮助程序方法:

private:
    auto find_handler(const std::string& name)
        -> decltype(handler_factory<X>().get(name))
    {
        return handler_factory<X>().get(name);
    }

然后你可以这样称呼它:

int main()
{
    X{}.dispatch_method("f", 5);
}

您可以使用如下内容:

#include <map>
#include <functional>
#include <stdexcept>
#include <string>
template<typename T> class Caller;
template<typename Ret, typename... Args>
class Caller<std::function<Ret(Args...)>>
{
public:
    typedef std::function<Ret(Args...)> FuncType;
    void add(const std::string& name, FuncType f)
    {
        functions[name] = f;
    }
    Ret call(const std::string& name, Args... args)
    {
        auto it = functions.find(name);
        if (it == functions.end()) {
            // Or any other error
            throw std::runtime_error("unknown " + name + "function");
        }
        return (it->second)(args...);
    }
private:
    std::map<std::string, FuncType> functions;
};

所以让我们测试一下:

int minus(int a) { return -a; }
int main(int argc, char** argv)
{
    Caller<std::function<int (int)>> caller;
    caller.add("+1", [](int a) { return a + 1; } );
    caller.add("minus", minus);
    caller.call("minus", -42); // calls minus(-42), returns 42
    caller.call("+1", 41);     // calls the lambda, returns 42
    return 0;
}

这类似于这里的问题。你需要创建一个像这样的映射map<string, class::method>,然后你可以使用它的签名来搜索函数并调用它。


有两种方法可供您使用:

1. 不使用任何第三方库(第 C++ 行):

    #include <map>
    #include <string>
    struct Math
    {
        double sinFunc(double x) { return 0.33; };
        double cosFunc(double x) { return 0.66; };
    };
    typedef double (Math::*math_method_t)(double);
    typedef std::map<std::string, math_method_t> math_func_map_t;
    int main()
    {
        math_func_map_t mapping;
        mapping["sin"] = &Math::sinFunc;
        mapping["cos"] = &Math::cosFunc;
        std::string function = std::string("sin");
        math_func_map_t::iterator x = mapping.find(function);
        int result = 0;
        if (x != mapping.end()) {
            Math m;
            result = (m.*(x->second))(20);
        }
    }

2. 通过使用 Boost 库:method最方便的表示法是function<signature> function包含在 boost<utility> 中。

签名将是这样的。

        map<string, function<double (double)> map; ...
        map["sin"](1.0);