Отображение функций с переменными аргументами и вызов по строке c ++

0

Я хотел бы иметь определенную идею о том, как сопоставлять функции с переменными аргументами, возвращать тип 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.. Но, похоже, сложные функции вызова с использованием строк.

  • 0
    Вы имеете в виду переменные аргументы, используя initializer_list?
  • 5
    Это требует использования эльфийской магии. Ты эльф?
Показать ещё 1 комментарий
Теги:
c++11

1 ответ

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. Создание функциональных карт name->

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-вставленный, чтобы сказать 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;
}
  • 0
    привет .. Могу ли я сделать карту со строкой и указателем на функцию void? Это просто моя логика не проверена ... скажем так ... typedef int (*TFPfunc1)(int, int ); typedef int (*TFPfunc2)(int , int , int* ); TFPfunc1 FPfunc1 = &func1; TFPfunc2 FPfunc2 = &func2; typedef int (*GenericFuncP)(); std::map<std::string, GenericFuncP)> MainMap; MainMap["func1"] = (TFPfunc1) FPfunc1; MainMap["func2"] = (TFPfunc2) FPfunc2;
  • 0
    @ Lo1234: Да, стандарт позволяет приводить указатель функции к другому типу указателя на функцию, при условии, что вы перед тем, как использовать его, вернете его к нужному типу указателя на функцию. Обратите внимание, что вместо того, чтобы приводить указатель функции к void * и обратно, работа не гарантируется (указатели на функции и указатели на данные могут иметь разный размер). Однако оператор должен быть MainMap["func1"]=(GenericFuncP)FPFunc1; для работы, и вы должны преобразовать его обратно в TFPfunc1 перед его использованием.
Показать ещё 2 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню