使用变量参数映射函数并通过字符串 c++ 调用

Mapping functions with variable arguments and calling by string c++

本文关键字:字符串 c++ 调用 变量 参数 映射函数      更新时间:2023-10-16

我想有一些公平的想法,如何使用变量参数映射函数,返回int类型并通过字符串调用它。
仅举个例子...

int func1(int a, int b);
int func2(int a1, int b1 , int* c1);
int func3(char* dummy);
int func4(double x, long y, int z, char** table);  
int func5(double d1, double b1);  
int func6(int* p, double* q, int i);

我只需要一个叫做

int CallFunction("funcname", param1, param2, ...); 

例如

CallFunction("func1", 10, 20); /* calling function func1 and return func1 result*/

我知道如何使用具有常量参数的函数指针映射函数,但变量参数似乎很复杂..任何人都可以知道如何做到这一点。

我什至探索了可变参数模板。但似乎使用字符串调用函数很复杂。

我遇到了完全相同的问题。

用这个解决方案解决了它:

#include <iostream>
#include <map>
#include <string>
int func0(int x)
{
    std::cout << x << std::endl;
}
int func1(int x, int y)
{
    std::cout << (x + y) << std::endl;
}
template <class... Args>
struct MapHolder{
    static std::map<std::string, int (*)(Args...)> CallbackMap;
};
template <class... Args>
std::map<std::string, int (*)(Args...)> MapHolder<Args...>::CallbackMap;
class Callback {
public:
    template <class ...Args>
    void RegisterFunction(std::string name, int (*func)(Args...)) { 
        MapHolder<Args...>::CallbackMap[name] = func;
    }
    template <class ...Args>
    int ExecuteFunction(std::string name, Args &&... args) { 
        return MapHolder<Args...>::CallbackMap[name](std::forward<Args>(args)...);
    };
};
int main(int argc, char *argv[])
{
    Callback cb;
    cb.RegisterFunction("func0", &func0);
    cb.RegisterFunction("func1", &func1);
    cb.ExecuteFunction("func0", 42);
    cb.ExecuteFunction("func1", 42, 42);
    return 0;
}

代码段基于此答案。我只使用其他类/函数名称。

我不确定这是否是您要找的,但无论如何...

1. 创建通用值持有者

boost.any没有进入标准,如果你不知道它是什么,它允许你将任何C++值存储在单个类型(any)中,如果你知道该类型,就可以取回它。以下是它的玩具实现:

struct TypeHandler {
    void* (*copyFrom)(void *src);
    void (*destroy)(void *p);
};
template<typename T>
TypeHandler *thandler() {
    struct THandler {
        static void *copyFrom(void *p) { return new T(*(T *)p); }
        static void destroy(void *p) { delete (T *)p; }
    };
    static TypeHandler th = { &THandler::copyFrom, &THandler::destroy };
    return &th;
}

TypeHandler包含两个指向知道如何复制以及如何销毁特定C++类型的函数的指针。Value可以保存任何类型,因为它由void *和指向TypeHandler的指针组成。当实例上需要复制或销毁时,它会要求特定的类型处理程序函数...

struct Value {
    TypeHandler *th;
    void *p;
    Value(const Value& other) : th(other.th), p(th->copyFrom(other.p)) { }
    template<typename T> Value(const T& x) : th(thandler<T>()), p(new T(x)) { }
    ~Value() { th->destroy(p); }
    Value& operator=(const Value& other) {
        if (this != &other) {
            th->destroy(p);
            th = other.th;
            p = th->copyFrom(other.p);
        }
        return *this;
    }
    template<typename T>
    Value& operator=(const T& other) {
        th->destroy(p);
        th = thandler<T>();
        p = new T(other);
        return *this;
    }
    template<typename T>
    T& to() const {
        if (th != thandler<T>()) throw Error("type mismatch");
        return *(T*)p;
    }
};

请注意,Value是可复制的,可以按值传递,也可以由函数返回。任何可复制的对象都可以隐式转换为Value,我也可以使用 to<T>() 将其转换回原始类型。

2. 创建名称>函数映射

std::map<std::string, Value (*)(const Value&)> map1;
std::map<std::string, Value (*)(const Value&, const Value&)> map2;
Value call(const std::string& name, const Value& x1) {
    return map1.at(name)(x1);
}
Value call(const std::string& name, const Value& x1, const Value& x2) {
    return map2.at(name)(x1, x2);
}

在这里,我为 1 和 2 参数创建了显式映射。也许这可以使用 C++11 个可变参数模板来完成,我没有尝试过。在 C++03 库中,经常看到这种东西复制粘贴到说 n=20 以涵盖合理情况。

3. 宏观学

为了简化函数的注册,我写了两个丑陋的宏。可能这也可以使用可变参数宏或模板来完成(我不太确定,尤其是在地图中自动注册包装器)。

#define regfunc1(name, t1)                   
    Value name(const Value& x1) {            
        return name(x1.to<t1>());            
    }                                        
    struct name##_ {                         
        name##_() { map1[#name]=&name; }     
    } name##_instance
#define regfunc2(name, t1, t2)                           
    Value name(const Value& x1, const Value& x2) {       
        return name(x1.to<t1>(), x2.to<t2>());           
    }                                                    
    struct name##_ {                                     
        name##_() { map2[#name]=&name; }                 
    } name##_instance

4. 使用

double square(double x) {
    return x*x;
}
double hyp2(double x, double y) {
    return x*x+y*y;
}
int mylen(const std::string& s) {
    return s.size();
}

regfunc1(square, double);
regfunc2(hyp2, double, double);
regfunc1(mylen, std::string);
int main() {
    Value x = 42;
    Value y = std::string("This is a test");
    Value z = 3.14;
    printf("%0.3fn", call("square", z).to<double>());
    printf("%0.3fn", call("hyp2", z, z).to<double>());
    printf("mylen("%s") = %in",
           y.to<std::string>().c_str(),
           call("mylen", y).to<int>());
    return 0;
}