Я хотел бы иметь определенную идею о том, как сопоставлять функции с переменными аргументами, возвращать тип 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.. Но, похоже, сложные функции вызова с использованием строк.
Я не уверен, что это то, что вы ищете, но в любом случае...
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>()
.
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, чтобы охватить разумные случаи.
Чтобы упростить регистрацию функций, я написал два уродливых макроса. Возможно, это можно сделать и с использованием переменных шаблонов или шаблонов (я не уверен в этом, особенно автоматическая регистрация обертки на карте).
#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
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;
}
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;
void *
и обратно, работа не гарантируется (указатели на функции и указатели на данные могут иметь разный размер). Однако оператор должен быть MainMap["func1"]=(GenericFuncP)FPFunc1;
для работы, и вы должны преобразовать его обратно в TFPfunc1
перед его использованием.