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

时间:2014-12-27 18:26:14

标签: c++ c++11

我想知道如何使用变量参数映射函数,返回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*/

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

我甚至探索了Variadic模板..但似乎使用字符串来复杂调用函数..

2 个答案:

答案 0 :(得分:1)

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

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。创建名称 - &gt;功能地图

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.3f\n", call("square", z).to<double>());
    printf("%0.3f\n", call("hyp2", z, z).to<double>());
    printf("mylen(\"%s\") = %i\n",
           y.to<std::string>().c_str(),
           call("mylen", y).to<int>());
    return 0;
}

答案 1 :(得分:0)

我有完全相同的问题。

使用以下解决方案解决了该问题:

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

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