How to define a method that receives a lambda expression?

4

I have a class similar to this and wanted the code it executed to be passed as a lambda expression.

class T {
public:
    double execute();
};

For example:

T t;
int a = 0, b = 1;
t.execute([a,b]()->double{return (3*a + 5*b);});

What would be the definition of the execute () method? Would it still be as it is? And the passage of the expression lambda would be anyway? I tried to infer how the code would look at this site: link

    
asked by anonymous 17.07.2016 / 22:48

2 answers

2

The OP found a solution using function pointers. He chose to pass the pointer through the constructor and store it in the class. Another possibility is to pass the function pointer directly to the function execute :

class T {
public:
    double execute(double (*expression)()) {
        return expression();
    }
};

int main() {
    T t;
    double result = t.execute([]() -> double {return 1 + 1;});
    return 0;
}

Function pointers have a strange syntax, do not allow capture of context variables (i.e., closures) and inlining .

See working on Ideone .

If you need closures or inline you can use a template to generalize the expression. For most cases this is the best way to pass any function as a parameter:

class T {
public:
    template<typename Func>
    double execute(Func expression) {
        return expression();
    }
};

int main() {
    T t;
    int a = 0, b = 1;
    double result = t.execute([&a,&b]() -> double {return 3 * a + 5 * b;}); 
    return 0;
}

The main limitations of the template version are:

  • Can not "store" this type outside the class
  • The implementation must be next to the header
  • See working on Ideone .

    If the above limitations are a problem, std::function , a wrapper for function pointers, functors , lambdas , etc.

    class T {
    public:
        double execute(std::function<double()> expression) {
            // sem templates, expression pode ser "armazenada" em qualquer lugar
            return expression();
        }
    };
    
    int main() {
        T t;
        int a = 0, b = 1;
        // [&] captura qualquer variavel por referencia
        std::function<double()> func = [&]() -> double {return 3 * a + 5 * b;};
        double result = t.execute(func);   
        return 0;
    }
    

    While the use of std::function is more generic when compared to function pointers, the wrapper results in overhead during the call. It is also not possible to use std::function with versions prior to C ++ 11 or with inline .

    See working on Ideone .

    References:

  • SOen: Should I use std :: function or a function pointer in C ++?
  • Lambda Functions in C ++ 11 - the Definitive Guide
  • 18.07.2016 / 14:39
    3

    I found the solution. It looks like this:

    class T {
    private:
        double (*expression)();
    public:
        T(double (*exp)()) : expression(exp) {}
        double execute() {
            return this->expression();
        }
    };
    
    int main() {
        T t([]()->double {return 1+1;});
        double val = t.execute(); // val = 2
        return 0;
    }
    

    It was not exactly how I wanted it but solved the problem.

        
    18.07.2016 / 01:55