Создание map c указателями на функции, содержащие разные прототипы С++
Реализую калькулятор с первоначальным приведением в обратную польскую запись и дальнейшим расчётом. В классе пытаюсь создать таблицу операторов, функций с приоритетами, и указателями на функции. Пытаюсь сделать это следующим образом:
//1 функция в строке, 2 приоритет, 3 кол.арг, 4 указатель
QMap<QChar, QPair<int, QPair<int, function(double(double, double))>>> table {
{'(', {0, 0, nulptr}},
{'+', {1, 2, add}} и т.д
};
Вопрос в следующем: как организовать структуру table, чтобы можно было хранить функции с разным числом аргументов(3-й параметр - число аргументов функции)
Ранее на Cи делал 2 массива функций, соотносил с последовательностью функций в строке, что в итоге приводило к усложнению добавления функций в калькулятор, т.к. приходилось править в нескольких местах.
typedef double (*F_1ARG)(double);
typedef double (*F_2ARG)(double, double);
#define INC_F_1ARG \
F_1ARG f_1arg[] = {c_usub, cos, sin, tan, acos, asin, atan, sqrt, log, log10}
#define INC_F_2ARG F_2ARG f_2arg[] = {c_add, c_sub, c_mul, c_div, fmod, pow}
double calculation(Deque *rpn, double x) {
INC_F_1ARG;
INC_F_2ARG;
int op;
double result, t_1, t_2;
const char *n_f_2arg = "+-*/A^";
const char *n_f_1arg = "CDEFGHIJKL";
Deque *stack = init_deque();
lexeme_t *t_l = rpn->head;
while (t_l) {
if (l_get_type_f(t_l) == VARIABLE) {
d_push_f(stack, NUMBER, x);
} else if (l_get_number_f(t_l, &t_1)) {
d_push_f(stack, NUMBER, t_1);
} else if (l_get_operation_f(t_l, &op)) {
if (strchr(n_f_2arg, op)) {
if (d_get_number_f(stack, &t_2)) free(d_pop_lexem_f(stack));
if (d_get_number_f(stack, &t_1)) free(d_pop_lexem_f(stack));
result = f_2arg[strchr(n_f_2arg, op) - n_f_2arg](t_1, t_2);
d_push_f(stack, NUMBER, result);
} else if (strchr(n_f_1arg, op)) {
if (d_get_number_f(stack, &t_1)) free(d_pop_lexem_f(stack));
result = f_1arg[strchr(n_f_1arg, op) - n_f_1arg](t_1);
d_push_f(stack, NUMBER, result);
}
}
t_l = t_l->next;
}
d_get_number_f(stack, &result);
d_free(stack);
free(stack);
return result;
}
RPN:
void convert_to_rpn(Deque *rpn, const char *infix) {
int op = 0;
char *p_str = (char *)infix;
Deque *stack = init_deque();
while (*p_str != '\n' && *p_str != '\0') {
if (*p_str == 'x') {
d_push_b(rpn, VARIABLE);
p_str++;
} else if (isdigit(*p_str)) {
d_push_b(rpn, NUMBER, strtod(p_str, &p_str));
} else if (is_function(*p_str)) {
d_push_f(stack, OPERATION, *p_str++);
} else if (is_operation(*p_str)) {
while (d_get_operation_f(stack, &op) && is_less_eq_p(*p_str, op))
d_push_lexem_b(rpn, d_pop_lexem_f(stack));
d_push_f(stack, OPERATION, *p_str++);
} else if (*p_str == '(') {
d_push_f(stack, OPERATION, *p_str++);
} else if (*p_str++ == ')') {
while (d_get_operation_f(stack, &op) && op != '(')
d_push_lexem_b(rpn, d_pop_lexem_f(stack));
free(d_pop_lexem_f(stack));
if (d_get_operation_f(stack, &op) && is_function(op))
d_push_lexem_b(rpn, d_pop_lexem_f(stack));
}
}
while (stack->head) d_push_lexem_b(rpn, d_pop_lexem_f(stack));
d_free(stack);
free(stack);
}
int get_priority(int op) {
int result = 6;
const char *s_op = "(+-*/A^BC";
const int p_op[9] = {0, 1, 1, 2, 2, 2, 3, 4, 4};
if (strchr(s_op, op)) result = p_op[strchr(s_op, op) - s_op];
return result;
}
Нашёл на просторах stackoverflow следующую реализацию в стиле Си:
int foo(int a, int b)
{
return a + b;
}
int bar(double x, double y, double z)
{
return x * y * z;
}
int main()
{
int (*f[])() = { foo, bar };
int a = f[0](2, 3);
int b = f[1](1., 2., 3.);
}
Хотелось бы реализовать подобное в стиле С++
Реализовал следующим образом, но есть проблема с операторами без функций nullptr
enum class e_farg_t { DEFAULT, F_1ARG, F_2ARG };
enum class e_priority_t {DEFAULT, L_PR, M_PR, H_PR, UNARY, FUNC};
QMap<QChar, QPair<e_priority_t, QPair<e_farg_t, std::variant<std::function<double(double, double)>, std::function<double(double)>>>>> m_fun_ptr {
// {'(', {e_priority_t::DEFAULT, {e_farg_t::DEFAULT, nullptr}}},
{'+', {e_priority_t::L_PR, {e_farg_t::F_2ARG, [](double lhs, double rhs) -> double {return lhs + rhs;}}}},
{'-', {e_priority_t::L_PR, {e_farg_t::F_2ARG, [](double lhs, double rhs) -> double {return lhs - rhs;}}}},
{'*', {e_priority_t::M_PR, {e_farg_t::F_2ARG, [](double lhs, double rhs) -> double {return lhs * rhs;}}}},
{'/', {e_priority_t::M_PR, {e_farg_t::F_2ARG, [](double lhs, double rhs) -> double {return lhs / rhs;}}}},
{'A', {e_priority_t::M_PR, {e_farg_t::F_2ARG, (double(*)(double, double))&std::fmod}}},
{'^', {e_priority_t::H_PR, {e_farg_t::F_2ARG, (double(*)(double, double))&std::pow}}},
// {'B', {e_priority_t::UNARY, {e_farg_t::DEFAULT, nullptr}}},
{'C', {e_priority_t::UNARY, {e_farg_t::F_1ARG, [](double a) -> double {return -a;}}}},
{'D', {e_priority_t::FUNC, {e_farg_t::F_1ARG, (double(*)(double))&std::cos}}},
{'E', {e_priority_t::FUNC, {e_farg_t::F_1ARG, (double(*)(double))&std::sin}}},
{'F', {e_priority_t::FUNC, {e_farg_t::F_1ARG, (double(*)(double))&std::tan}}},
{'G', {e_priority_t::FUNC, {e_farg_t::F_1ARG, (double(*)(double))&std::acos}}},
{'H', {e_priority_t::FUNC, {e_farg_t::F_1ARG, (double(*)(double))&std::asin}}},
{'I', {e_priority_t::FUNC, {e_farg_t::F_1ARG, (double(*)(double))&std::atan}}},
{'J', {e_priority_t::FUNC, {e_farg_t::F_1ARG, (double(*)(double))&std::sqrt}}},
{'K', {e_priority_t::FUNC, {e_farg_t::F_1ARG, (double(*)(double))&std::log}}},
{'L', {e_priority_t::FUNC, {e_farg_t::F_1ARG, (double(*)(double))&std::log10}}}
};