Thread: Templates, lambdas and overloaded operators

  1. #1
    Ultraviolence Connoisseur
    Join Date
    Mar 2004
    Posts
    555

    Templates, lambdas and overloaded operators

    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.

  2. #2
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108
    O_o

    Yog Sothoth!

    Your code is atrocious. I am expecting a post with const-correct code.

    In any event, the result of evaluating a complex is not necessarily related to the type contained because your operators always resolve to the contained type.

    In other words, the type `execute' returns within the complex is `Operation<int>' not the resulting `int' from evaluating `Operation<int>("+", 5, 5) + Operation<int>("-", 3, 0)' that you want.

    You need to condition the type `execute' and friends return based on whether or not the contained is an expression or a complex.

    The evaluated `int' returned from the complex will then chain properly to the client.

    [Edit]
    Because you are already using C++11 features, you could use C++11 features to resolve the type instead of developing a solution.

    You can just throw `auto' and `decltype' at most of the utilities and overloads.
    [/Edit]

    Soma

    Code:
    template
    <
        typename T
    >
    struct result; // ...
    Code:
    template<typename T>
    typename result<T>::value Operation<T>::execute() const;
    Last edited by phantomotap; 02-16-2015 at 07:47 PM.
    “Salem Was Wrong!” -- Pedant Necromancer
    “Four isn't random!” -- Gibbering Mouther

  3. #3
    Ultraviolence Connoisseur
    Join Date
    Mar 2004
    Posts
    555
    Quote Originally Posted by phantomotap View Post
    O_o

    Yog Sothoth!

    Your code is atrocious. I am expecting a post with const-correct code.
    I'll be sure to read up on what I'm missing in that department, I know I'm lacking in explicity.

    As for the rest of your post, thank you very much that was just the advice I was looking for.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Overloaded operators
    By Kayoss in forum C++ Programming
    Replies: 6
    Last Post: 04-17-2006, 02:23 PM
  2. Templates and overloaded ==
    By prog-bman in forum C++ Programming
    Replies: 2
    Last Post: 02-16-2005, 09:22 PM
  3. Problem with overloaded operators, templates and inheritance
    By bleakcabal in forum C++ Programming
    Replies: 1
    Last Post: 03-19-2004, 05:07 AM
  4. overloaded operators
    By jccharl in forum C++ Programming
    Replies: 2
    Last Post: 03-14-2004, 06:14 PM
  5. overloaded operators
    By ivandn in forum C++ Programming
    Replies: 2
    Last Post: 12-20-2001, 03:52 PM