How to define a method that receives a lamppost expression?

Asked

Viewed 178 times

4

I have a class similar to this one and I wanted the code she executed to be passed as a blank 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 continue as it is? And would the passage of the phrase lâmbda be like that? I tried to infer what the code would be like looking at this site: http://en.cppreference.com/w/cpp/language/lambda

2 answers

3

I found the solution. She was 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 wasn’t exactly how I wanted it but it solved the problem.

2


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 capturing context variables (i.e, closures) and inlining.

See it working on Ideone.


In case you need closures or inline it is possible to 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 version with template sane:

  1. Cannot "store" this type outside the class
  2. The implementation needs to be close to the header

See it working on Ideone.


If the above limitations are a problem, it is possible to resort to std::function, one wrapper for function pointers, functors, Amble, 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 using 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 it working on Ideone.


References:

  1. Soen: Should I use Std::Function or a Function Pointer in C++?
  2. Lambda Functions in C++11 - the Definitive Guide
  • Very good this solution with the rapper. The advantage of being able to be stored stands out over the disadvantage of overhead. In addition the syntax is much clearer.

  • Yes, to be fair you could "store" a reference using the template within the class itself (the biggest flaw in my opinion of this approach, in my opinion, is that function templates do not work right with auto). That said, from the point of view of design std::function is really quite flexible.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.