What I'm trying to do is create a class for constructing an 'op tree' for parsing infix notation.
I started with a base class that uses a map of lambdas to actually calculate the operations (since they are mostly 1 line functions) of passed in integer or float values.
This base class just uses a templated T type as the lvalue and rvalue. I realized though that if I overload the math operators, +, -, etc.. I could also use the class itself as a type for the lvalue and rvalue. This lead me to think I could easily create the op tree by using Operation class members themselves as operands, which I think makes sense but I'm having some trouble expressing the code.
Heres what I have thus far
Code:
#include <map>
#include <string>
#include <algorithm>
#include <iostream>
namespace Calc {
template<typename T>
struct Operation {
Operation() = default;
Operation(const Operation&) = default;
Operation(Operation&&) = default;
Operation(std::string op, T rval=0, T lval=0) : opsymbol{op}, rvalue{rval}, lvalue{lval} { }
T execute();
const std::string& symbol() { return opsymbol; }
T rval() { return rvalue; }
T lval() { return lvalue; }
friend T operator+(const Operation<T>& rval, const Operation<T>& lval)
{
return rval.execute() + lval.execute();
}
friend T operator-(const Operation<T>& rval, const Operation<T>& lval)
{
return rval.execute() - lval.execute();
}
friend T operator/(const Operation<T>& rval, const Operation<T>& lval)
{
return rval.execute() / lval.execute();
}
friend T operator*(const Operation<T>& rval, const Operation<T>& lval)
{
return rval.execute() * lval.execute();
}
private:
std::string opsymbol;
T rvalue;
T lvalue;
};
template<typename T>
T Operation<T>::execute()
{
static const std::map<std::string, std::function<T(T,T)>> opfunc = {
{"+", [](T rval, T lval) -> T { return rval + lval; } },
{"-", [](T rval, T lval) -> T { return rval - lval; } },
{"*", [](T rval, T lval) -> T { return rval * lval; } },
{"/", [](T rval, T lval) -> T { return rval / lval; } },
};
T ret;
if (opfunc.count(opsymbol)) { /* If exists in map.. */
const auto& func = opfunc.at(opsymbol);
ret = func(rvalue, lvalue);
}
return ret;
}
}
int main(void)
{
Calc::Operation<double> plus{"+", 5, 5};
Calc::Operation<double> minus{"-", 5, 5};
Calc::Operation<double> times{"*", 5, 5};
Calc::Operation<Calc::Operation<int>> tree{"+",
{"+", 5, 5}, {"-", 3, 0}
};
std::cout << plus.execute() << std::endl;
std::cout << minus.execute() << std::endl;
std::cout << times.execute() << std::endl;
int result = tree.execute();
// std::cout << tree.execute() << std::endl;
return 0;
}
I'm getting the following errors when compiling:
Code:
$ g++ -o calc calculator.cc -std=c++11 -Wall
calculator.cc: In instantiation of ‘Calc::Operation<T>::execute() [with T = Calc::Operation<int>]::<lambda(Calc::Operation<int>, Calc::Operation<int>)>’:
calculator.cc:53:20: required from ‘struct Calc::Operation<T>::execute() [with T = Calc::Operation<int>]::<lambda(struct Calc::Operation<int>, struct Calc::Operation<int>)>’
calculator.cc:57:9: required from ‘T Calc::Operation<T>::execute() [with T = Calc::Operation<int>]’
calculator.cc:83:18: required from here
calculator.cc:53:59: error: could not convert ‘Calc::operator+((*(const Calc::Operation<int>*)(& rval)), (*(const Calc::Operation<int>*)(& lval)))’ from ‘int’ to ‘Calc::Operation<int>’
calculator.cc:54: confused by earlier errors, bailing out
I was hoping I could get some tips on how to structure this whole idea and how to procede with the concept I'm trying to acheive.
Example, if you look at the main() function I create normal operations easily with integer values. I then try to create a "tree" operation that includes 2 sub-operations as it's rvalue and lvalue, that is where I'm having some conceptual problems as far as implementing the code to do that.