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}
};
}
};
}
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
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.
Related
I'm working on a programme to calculate average acceleration and i use 3 function ( by pass reference method) after writing my code this error happens
and "error C2082: redefinition of formal parameter 'Vo'".I've google it and i barely understand it.Can anyone explain to me why this happens and how to solve this?thank you for helping
/* lab assessment 4 kiraan pecutan*/
#include <iostream>
using namespace std;
void data(double& Vo,double& Vt,double& t);
void calculate(double& sum);
void output(double& out);
double Vo,Vt,t,sum,out;
int main()
{
cout<<"please enter your velocity(Vo=m/s)\n,velocity(Vt=m/s)\nand time(s=second)\n\n";
data(Vo,Vt,t);
calculate(sum);
output( out);
return 0;
}
void data(double& Vo,double& Vt,double& t)
{
double Vo,Vt,t;
cin>>Vo;
cin>>Vt;
cin>>t;
cout<<"your Vo="<<Vo<<" ,Vt="<<Vt<<" and T="<<t<<"\n\n";
}
void calculate(double& sum )
{
double Vt,Vo,t;
sum=(Vt-Vo)/t;
}
void output(double& out)
{
double sum;
cout<<"the acceleration ="<<sum;
}
You declare variables with the same name multiple times. Each variable defined by its name should be declared exactly ones. It is not allowed to use the same variable name e.g. as a function parameter and a variable name in the function body, e.g.
void data(double &Vo) {
double Vo = 0.0; // Vo already exists with type double&
// do something
}
Please consider the following hints:
do not use global variables unless necessary, they are hard to debug in big projects
always initialize variables of basic types (int, float, double, ...) with a value otherwise they get a 'random' one
The following code should compile without errors, even though the semantic/computation maybe wrong. I just used your implementation.
#include <iostream>
using namesace std;
//--------------------------------------------------------------------------//
void data(double &Vo, double &Vt, double &t);
void calculate(double &Vo, double &Vt, double &t, double &sum);
void output(double &out);
//--------------------------------------------------------------------------//
int main() {
double Vo = 0.0;
double Vt = 0.0;
double t = 0.0;
double sum = 0.0;
double out = 0.0;
cout << "please enter your velocity(Vo=m/s)\n,velocity(Vt=m/s)\nand time(s=second)\n\n";
data(Vo, Vt, t);
calculate(Vo, Vt, t, sum);
output(out);
return 0;
}
//--------------------------------------------------------------------------//
void data(double &Vo, double &Vt, double &t) {
cin >> Vo;
cin >> Vt;
cin >> t;
cout << "your Vo=" << Vo << " ,Vt=" << Vt << " and T=" << t << "\n\n";
}
//--------------------------------------------------------------------------//
void calculate(double &Vo, double &Vt, double &t, double &sum) {
sum = (Vt - Vo) / t;
}
//--------------------------------------------------------------------------//
void output(double &out) {
cout << "the acceleration =" << out;
}
I got a (potentially) unlimited set of functions with the same signature, which all live in the same namespace:
namespace cost_functions
{
int calculate_cost_1(std::vector<double> waypoints, double time);
int calculate_cost_2(std::vector<double> waypoints, double time);
...
int calculate_cost_n(std::vector<double> waypoints, double time);
}
And I want to get these functions into a vector dynamically, such that I can iterate over them in the following way:
auto waypoints = get_waypoints();
auto t = get_time();
auto cost_functions = get_all_cost_functions();
auto total_cost = 0;
for(cost_function:cost_functions)
{
total_cost += cost_function();
}
How do I have to implement get_all_cost_functions()? Is there some kind of reflexion in C++14?
Is there some kind of reflexion in C++14?
No there is no reflection.
How do I have to implement get_all_cost_functions()?
Something along the lines of
const std::vector<std::function<int (std::vector<double>,double)>>&
get_all_cost_functions() {
static std::vector<std::function<int (std::vector<double>,double)>> funcs {
calculate_cost_1 ,
calculate_cost_2 ,
calculate_cost_3 ,
calculate_cost_4 ,
calculate_cost_5 ,
calculate_cost_6 ,
//
calculate_cost_xx ,
};
return funcs;
}
Here's another idea (probably easier to manage when additional cost calculation functions should be added in future):
#include <iostream>
#include <functional>
#include <vector>
namespace cost_functions
{
class CostFunctionRegistrar {
public:
typedef std::function<int (std::vector<double>,double)> CostCalulationFunc;
CostFunctionRegistrar(std::function<int (std::vector<double>,double)> func) {
allCostCalculationFuncs.push_back(func);
}
static const std::vector<CostCalulationFunc>& get_all_cost_functions() {
return allCostCalculationFuncs;
}
private:
static std::vector<CostCalulationFunc> allCostCalculationFuncs;
};
std::vector<CostFunctionRegistrar::CostCalulationFunc> CostFunctionRegistrar::allCostCalculationFuncs;
int calculate_cost_1(std::vector<double> waypoints, double time) {
std::cout << "calculate_cost_1" << std::endl;
return 0;
}
static CostFunctionRegistrar r1(calculate_cost_1);
int calculate_cost_2(std::vector<double> waypoints, double time) {
std::cout << "calculate_cost_2" << std::endl;
return 0;
}
static CostFunctionRegistrar r2(calculate_cost_2);
int calculate_cost_n(std::vector<double> waypoints, double time) {
std::cout << "calculate_cost_n" << std::endl;
return 0;
}
static CostFunctionRegistrar rn(calculate_cost_n);
}
int main()
{
for(auto cost_calc : cost_functions::CostFunctionRegistrar::get_all_cost_functions()) {
std::vector<double> waypoints;
double time = 0;
cost_calc(waypoints,time);
}
}
See the live demo working here.
I'm trying to create a program to numerically integrate a function between two limits. I've created a minimal example (where the "integral" is always 1.0) to illustrate an error I get. The code below tries to use a function whose arguments are two doubles and a function from doubles to doubles:
#include <iostream>
#include <math.h>
double cons(double a, double b, double c(double d))
{
return 1.0;
}
double f(double x)
{
return x*x;
}
int main()
{
double x;
double I = cons(0, 1, f(x));
std::cout << I << "";
}
This results in an error on cpp.sh:
14:31: error: cannot convert 'double' to 'double ()(double)' for argument '3' to 'double cons(double, double, double ()(double))'
Obviously, the difference between doubles and double-valued functions is causing a problem here. How can I get this working?
You need to pass the function, not call it.
#include <iostream>
#include <math.h>
double cons(double a, double b, double c(double d))
{
return 1.0;
}
double f(double x)
{
return x*x;
}
int main()
{
double x;
double I = cons(0, 1, f);
std::cout << I << "";
}
You didn't pass a function but the result of a function, a double. Second, you didn't correctly declared a function pointer as argument.
If you want to pass a double then declare a double as argument:
double cons(double a, double b, double c)
{
return 1.0*a*b*c;
}
double f(double x)
{
return x*x;
}
int main()
{
double x;
double I = cons(0, 1, f(x));
std::cout << I << "";
}
If you want to pass a function (aka function pointer as C++ is not a functional language):
double cons(double a, double b, double (*c)(double d))
{
return 1.0*c(a);
}
double f(double x)
{
return x*x;
}
int main()
{
double x;
double I = cons(0, 1, f);
std::cout << I << "";
}
Your problem in this case is that you are calling the function with:
double I = cons(0, 1, f(x));
so you actually give cons the return value of f() instead of the actual function. So you need to write this insteed:
double I = cons(0, 1, f);
As an alternativ you could also use lambda expressions for your problem. For example something like this:
#include <iostream>
#include <math.h>
#include <functional>
double cons(double a, double b, const std::function<double(double)>& callback)
{
// do something
}
int main()
{
double x;
double I = cons(0, 1, [](double x){ return x*x});
std::cout << I << "";
}
I'd like advice on a way to cache a computation that is shared by two derived classes. As an illustration, I have two types of normalized vectors L1 and L2, which each define their own normalization constant (note: against good practice I'm inheriting from std::vector here as a quick illustration-- believe it or not, my real problem is not about L1 and L2 vectors!):
#include <vector>
#include <iostream>
#include <iterator>
#include <math.h>
struct NormalizedVector : public std::vector<double> {
NormalizedVector(std::initializer_list<double> init_list):
std::vector<double>(init_list) { }
double get_value(int i) const {
return (*this)[i] / get_normalization_constant();
}
virtual double get_normalization_constant() const = 0;
};
struct L1Vector : public NormalizedVector {
L1Vector(std::initializer_list<double> init_list):
NormalizedVector(init_list) { }
double get_normalization_constant() const {
double tot = 0.0;
for (int k=0; k<size(); ++k)
tot += (*this)[k];
return tot;
}
};
struct L2Vector : public NormalizedVector {
L2Vector(std::initializer_list<double> init_list):
NormalizedVector(init_list) { }
double get_normalization_constant() const {
double tot = 0.0;
for (int k=0; k<size(); ++k) {
double val = (*this)[k];
tot += val * val;
}
return sqrt(tot);
}
};
int main() {
L1Vector vec{0.25, 0.5, 1.0};
std::cout << "L1 ";
for (int k=0; k<vec.size(); ++k)
std::cout << vec.get_value(k) << " ";
std::cout << std::endl;
std::cout << "L2 ";
L2Vector vec2{0.25, 0.5, 1.0};
for (int k=0; k<vec2.size(); ++k)
std::cout << vec2.get_value(k) << " ";
std::cout << std::endl;
return 0;
}
This code is unnecessarily slow for large vectors because it calls get_normalization_constant() repeatedly, even though it doesn't change after construction (assuming modifiers like push_back have appropriately been disabled).
If I was only considering one form of normalization, I would simply use a double value to cache this result on construction:
struct NormalizedVector : public std::vector<double> {
NormalizedVector(std::initializer_list<double> init_list):
std::vector<double>(init_list) {
normalization_constant = get_normalization_constant();
}
double get_value(int i) const {
return (*this)[i] / normalization_constant;
}
virtual double get_normalization_constant() const = 0;
double normalization_constant;
};
However, this understandably doesn't compile because the NormalizedVector constructor tries to call a pure virtual function (the derived virtual table is not available during base initialization).
Option 1:
Derived classes must manually call the normalization_constant = get_normalization_constant(); function in their constructors.
Option 2:
Objects define a virtual function for initializing the constant:
init_normalization_constant() {
normalization_constant = get_normalization_constant();
}
Objects are then constructed by a factory:
struct NormalizedVector : public std::vector<double> {
NormalizedVector(std::initializer_list<double> init_list):
std::vector<double>(init_list) {
// init_normalization_constant();
}
double get_value(int i) const {
return (*this)[i] / normalization_constant;
}
virtual double get_normalization_constant() const = 0;
virtual void init_normalization_constant() {
normalization_constant = get_normalization_constant();
}
double normalization_constant;
};
// ...
// same code for derived types here
// ...
template <typename TYPE>
struct Factory {
template <typename ...ARGTYPES>
static TYPE construct_and_init(ARGTYPES...args) {
TYPE result(args...);
result.init_normalization_constant();
return result;
}
};
int main() {
L1Vector vec = Factory<L1Vector>::construct_and_init<std::initializer_list<double> >({0.25, 0.5, 1.0});
std::cout << "L1 ";
for (int k=0; k<vec.size(); ++k)
std::cout << vec.get_value(k) << " ";
std::cout << std::endl;
return 0;
}
Option 3:
Use an actual cache: get_normalization_constant is defined as a new type, CacheFunctor; the first time CacheFunctor is called, it saves the return value.
In Python, this works as originally coded, because the virtual table is always present, even in __init__ of a base class. In C++ this is much trickier.
I'd really appreciate the help; this comes up a lot for me. I feel like I'm getting the hang of good object oriented design in C++, but not always when it comes to making very efficient code (especially in the case of this sort of simple caching).
I suggest the non-virtual interface pattern. This pattern excels when you want a method to provide both common and unique functionality. (In this case, caching in common, computation in uniqueness.)
http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Non-Virtual_Interface
// UNTESTED
struct NormalizedVector : public std::vector<double> {
...
double normalization_constant;
bool cached;
virtual double do_get_normalization_constant() = 0;
double get_normalization_constant() {
if(!cached) {
cached = true;
normalization_constant = do_get_normalization_constant();
}
return normalization_constant;
};
P.s. You really ought not publicly derive from std::vector.
P.P.s. Invalidating the cache is as simple as setting cached to false.
Complete Solution
#include <vector>
#include <iostream>
#include <iterator>
#include <cmath>
#include <algorithm>
struct NormalizedVector : private std::vector<double> {
private:
typedef std::vector<double> Base;
protected:
using Base::operator[];
using Base::begin;
using Base::end;
public:
using Base::size;
NormalizedVector(std::initializer_list<double> init_list):
std::vector<double>(init_list) { }
double get_value(int i) const {
return (*this)[i] / get_normalization_constant();
}
virtual double do_get_normalization_constant() const = 0;
mutable bool normalization_constant_valid;
mutable double normalization_constant;
double get_normalization_constant() const {
if(!normalization_constant_valid) {
normalization_constant = do_get_normalization_constant();
normalization_constant_valid = true;
}
return normalization_constant;
}
void push_back(const double& value) {
normalization_constant_valid = false;
Base::push_back(value);
}
virtual ~NormalizedVector() {}
};
struct L1Vector : public NormalizedVector {
L1Vector(std::initializer_list<double> init_list):
NormalizedVector(init_list) { get_normalization_constant(); }
double do_get_normalization_constant() const {
return std::accumulate(begin(), end(), 0.0);
}
};
struct L2Vector : public NormalizedVector {
L2Vector(std::initializer_list<double> init_list):
NormalizedVector(init_list) { get_normalization_constant(); }
double do_get_normalization_constant() const {
return std::sqrt(
std::accumulate(begin(), end(), 0.0,
[](double a, double b) { return a + b * b; } ) );
}
};
std::ostream&
operator<<(std::ostream& os, NormalizedVector& vec) {
for (int k=0; k<vec.size(); ++k)
os << vec.get_value(k) << " ";
return os;
}
int main() {
L1Vector vec{0.25, 0.5, 1.0};
std::cout << "L1 " << vec << "\n";
vec.push_back(2.0);
std::cout << "L1 " << vec << "\n";
L2Vector vec2{0.25, 0.5, 1.0};
std::cout << "L2 " << vec2 << "\n";
vec2.push_back(2.0);
std::cout << "L2 " << vec2 << "\n";
return 0;
}
A quick and dirty solution is to use static member variable.
double get_normalization_constant() const {
static double tot = 0.0;
if( tot == 0.0 )
for (int k=0; k<size(); ++k)
tot += (*this)[k];
return tot;
}
In this case, it will only be computed once.. and each time it will return the latest value.
NOTE:
This double tot, will be shared will all objects of same type. Don't use it if you will create many object of the type L1Vector
In this program Iam trying to take 78 degrees Fahrenheit and return them in a class with the Celsius version and kelvin. But for some odd reason I'm just getting this as the output. What am I doing wrong?
This is my output.
78
0
273.15
#include <iostream>
using namespace std;
class Temperature
{
public:
double getTempKelvin();
double getTempFahrenheit();
double getTempCelcius();
void setTempKelvin(double k);
void setTempFahrenheit(double f);
void setTempCelcius(double c);
private:
double kelvin, fahrenheit, celcius;
double c, f, k;
};
int main ()
{
double c, f, k;
Temperature Conv;
Conv.setTempFahrenheit(f);
Conv.setTempCelcius(c);
Conv.setTempKelvin(k);
cout << Conv.getTempFahrenheit() << endl;
cout << Conv.getTempCelcius() << endl;
cout << Conv.getTempKelvin() << endl;
return 0;
}
void Temperature::setTempFahrenheit(double f)
{
f = 78;
fahrenheit = f;
}
void Temperature::setTempCelcius(double c)
{
c = (5/9) * ( f - 32);
celcius = c;
}
void Temperature::setTempKelvin(double k)
{
k = c + 273.15;
kelvin = k;
}
double Temperature::getTempFahrenheit()
{
return fahrenheit;
}
double Temperature::getTempCelcius()
{
return celcius;
}
double Temperature::getTempKelvin()
{
return kelvin;
}
5/9 is integer division and will result in 0. You need to use doubles, Try:
void Temperature::setTempCelcius(double c)
{
c = (5.0/9.0) * ( f - 32);
celcius = c;
}
Aside from the 5/9 issue, you have three sets of variables called 'c', 'f', and 'k'. One set are the member variables in the class. Another set are the variables in main. The third set are the parameters inside the various get* functions.
It's not clear what purpose the variables in main serve, why the functions take parameters at all, or why your class has two sets of variables for the temperatures (both c and celsius, and so on) but if you give the sets of variables different names, it will become easier to understand why your program isn't working.
Seems that my problem was that i was clearning the k c and f double so i just removed them from the functions.
#include <iostream>
using namespace std;
double c, f, k;
class Temperature
{
public:
double getTempKelvin();
double getTempFahrenheit();
double getTempCelcius();
void setTempKelvin();
void setTempFahrenheit();
void setTempCelcius();
private:
double kelvin, fahrenheit, celcius;
double c, f, k;
};
int main ()
{
Temperature Conv;
Conv.setTempFahrenheit();
Conv.setTempCelcius();
Conv.setTempKelvin();
cout << Conv.getTempFahrenheit() << endl;
cout << Conv.getTempCelcius() << endl;
cout << Conv.getTempKelvin() << endl;
return 0;
}
void Temperature::setTempFahrenheit(){
f = 78;
fahrenheit = f;
}
void Temperature::setTempCelcius()
{
c = (5.0/9.0) * ( f - 32);
celcius = c;
}
void Temperature::setTempKelvin()
{
k = c + 273.15;
kelvin = k;
}
double Temperature::getTempFahrenheit()
{
return fahrenheit;
}
double Temperature::getTempCelcius()
{
return celcius;
}
double Temperature::getTempKelvin()
{
return kelvin;
}
#include<iostream>
using namespace std;
class temperature
{
public :
virtual void calculate(float)=0;
};
class ftoc : public temperature
{
public :
float c;
void calculate(float f)
{
c=(f-32)*5/9;
cout<<"Temperature in celcius is : "<<c<<" `C "<<endl;
}
};
class ftok : public temperature
{
public :
float k;
void calculate(float f)
{
k=(f+459.67)*5/9;
cout<<"Themperature in kelvin is : "<<k<<" K "<<endl;
}
};
int main()
{
float f;
ftoc a;
ftok b;
cout<<"Enter the temperature : ";
cin>>f;
a.calculate(f);
b.calculate(f);
return 0;
}