chixken_tendies
chixken_tendies

Reputation: 29

Calling functions and passing arguments through map in c++?

I've been trying to figure out how I can use std::map to call functions and pass arguments to said functions based on a key.

I'm translating a project I made in Python to C++, but I've been stuck on this, and I really don't want to resort to a mess of if-elses.

The way I did that in Python was as so:

return_operation = {  
    "*": Operations.multiply,  
    "^": Operations.exponent,  
    "**": Operations.exponent
    etc...
}

result = return_operation["*"](num_1, num_2)

Is there some sort of way to accomplish this is C++? I've tried using std::map but I keep getting:

Error C2276 '&': illegal operation on bound member function expression.

I'm still very new to C++ and I'm totally lost.

namespace std{
    class Calculator {

    public:
        void multiply(double num_1, double num_2) {
            cout << "MULTIPLYING!" << endl;
            // Normally it would return the result of multiplying the two nums
            // but it only outputs to the console until I can figure this out.
        }

        void initialize() {
            void (Calculator::*funcPtr)();
            funcPtr = &multiply;

            unordered_map<string, Calculator()> operator_function = {
                {"*", &multiply}
            };
        }
    };
}

Upvotes: 1

Views: 189

Answers (2)

Remy Lebeau
Remy Lebeau

Reputation: 598448

First off, you can't add custom types to the std namespace. Only specializations of existing templates.

Second, you are using the wrong mapped type for the unordered_map. Try something more like this instead:

class Calculator {
private:
    typedef double (Calculator::*FuncType)(double, double);

    unordered_map<string, FuncType> operator_function = {
        {"*",  &Calculator::multiply},
        {"^",  &Calculator::exponent},
        {"**", &Calculator::exponent}
        // and so on ...
    };

    double multiply(double num_1, double num_2) {
        cout << "MULTIPLYING!" << endl;
        return num_1 * num_2;
    }

    double exponent(double num_1, double num_2) {
        cout << "EXPONENT!" << endl;
        return pow(num_1, num_2);
    }

public:
    double do_math(string op, double num_1, double num_2) {
        FuncType func = operator_function[op];
        return (this->*func)(num_1, num_2);
    }
};

Then, to call a function in the map, you can do this:

Calculator calc;
...
double result = calc.do_math("*", num_1, num_2);

Online Demo

Alternatively, Calculator doesn't really need to be stateful in this example, so the methods could be static to avoid needing an actual Calculator object:

class Calculator {
private:
    typedef double (*FuncType)(double, double);

    static unordered_map<string, FuncType> operator_function;

    static double multiply(double num_1, double num_2) {
        cout << "MULTIPLYING!" << endl;
        return num_1 * num_2;
    }

    static double exponent(double num_1, double num_2) {
        cout << "EXPONENT!" << endl;
        return pow(num_1, num_2);
    }

public:
    static double do_math(string op, double num_1, double num_2) {
        FuncType func = operator_function[op];
        return func(num_1, num_2);
    }
};
unordered_map<string, Calculator::FuncType> Calculator::operator_function = {
    {"*",  &Calculator::multiply},
    {"^",  &Calculator::exponent},
    {"**", &Calculator::exponent}
    // and so on ...
};
double result = Calculator::do_math("*", num_1, num_2);

Online Demo

Alternatively, you could use lambdas instead of class methods, eg:

class Calculator {
private:
    using FuncType = std::function<double(double, double)>;

    static unordered_map<string, FuncType> operator_function;

public:
    static double do_math(string op, double num_1, double num_2) {
        if (op == "**") op = "^";
        FuncType func = operator_function[op];
        return func(num_1, num_2);
    }
};
unordered_map<string, Calculator::FuncType> Calculator::operator_function = {
    {"*", [](double num_1, double num_2)
            {
                cout << "MULTIPLYING!" << endl;
                return num_1 * num_2;
            }
    },
    {"^", [](double num_1, double num_2)
            {
                cout << "EXPONENT!" << endl;
                return pow(num_1, num_2);
            }
    }
    // and so on ...
};
double result = Calculator::do_math("*", num_1, num_2);

Online Demo

Upvotes: 4

Markus Mayr
Markus Mayr

Reputation: 4118

If you're looking for a straight translation of your python code, then I'd go with something like this:

#include <cmath>
#include <functional>
#include <iostream>
#include <unordered_map>

int main() {
    std::unordered_map<std::string, std::function<double (double, double)>> return_operation{
      { "*", [](double a, double b) { return a * b; } },
      { "^", [](double a, double b) { return std::pow(a, b); } },
    };

    double r = return_operation["*"](5, 3); // r == 15
    std::cout << r << std::endl;
    return 0;
}

From a learning perspective, I totally recommend the answer by Remy Lebeau.

Upvotes: 2

Related Questions