Reputation: 29
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-else
s.
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
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);
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);
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);
Upvotes: 4
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