Converting a two-stage function std :: to a single-interval

I have a function that takes two values: x and y and returns the result:

std::function< double( double, double ) > mult = []( double x, double y){ return x*y; }; 

Now I want to get a function with one variable for constant y. I wrote the following code, but it does not work.

 std::function< std::function< double(double) > ( std::function< double(double, double) >, double ) > funcYgivenX = [](std::function< double(double, double) > func2d, double inX) { return [&func2d, &inX]( double inY ) { return func2d(inX, inY); }; }; 

What am I doing wrong here? And what is the best (most efficient) way to do this?

+4
source share
3 answers

In C ++ 11, std::bind is deprecated significantly with the introduction of lambdas . Here is an example of binding using lambda.

 int add(int a, int b) {return a + b;} int main() { auto add2 = [](int a){ return add(a,2); }; std::cout << add2(3) << std::endl; // prints 5 } 

For reference on lambda preference over std::bind you can read Scott Meyers' Effective Modern C ++, paragraph 32. In C ++ 11, it is not possible to move a capture using lambda, and this behavior can only be emulated with std::bind . With the introduction of init capture for lambdas in C ++ 14, even this angular case can be well resolved with lambdas.

+9
source

No no. This is what std::bind exists for!

 #include <iostream> #include <functional> #include <typeinfo> int add(int a, int b) {return a + b;} int main() { //I believe this here is just a special type of bound function. auto add2 = std::bind(add, std::placeholders::_1, 2); //Yup. std::cout << typeid(add2).name() << std::endl; //Here the type of the first function. std::cout << typeid(add).name() << std::endl; //The new function. std::cout << add2(1) << std::endl; return 0; } 

http://coliru.stacked-crooked.com/a/56c0459617ba61d5

All you do is provide a function, and then the arguments that you want to pass to the new function as secondary arguments in std::bind , and replace any "empty spaces" with "std :: placeholders :: _ X", where X is the number of the nth argument, starting at 1 for the first argument.

You can even implement closure!

http://coliru.stacked-crooked.com/a/0b43fe3d1651fe36

 #include <iostream> #include <functional> #include <typeinfo> #include <vector> int add(int a, int b) {return a + b;} int main() { std::vector<std::function<int(int)>> funcs; for (int i = 0; i < 5; ++i) { auto f = std::bind(add, std::placeholders::_1, i+1); funcs.push_back(f); } int i = 0; for (int k = 0; k > -10; k = k - 2) { std::cout << funcs[i](k) << std::endl; ++i; } return 0; } 

If you want, you can also use lambdas; they are also cleaner and you can probably avoid the nasty std::bind types:

http://coliru.stacked-crooked.com/a/9df068bc41beb8ea

 #include <iostream> #include <functional> #include <typeinfo> #include <vector> int add(int a, int b) {return a + b;} int main() { std::vector<std::function<int(int)>> funcs; for (int i = 0; i < 5; ++i) { auto f = [i](int j) {return(i + j);}; funcs.push_back(f); } int i = 0; for (int k = 0; k > -10; k = k - 2) { std::cout << funcs[i](k) << std::endl; ++i; } return 0; } 
+4
source

When you use

 return [&func2d, &inX]( double inY ){ return func2d(inX, inY); }; 

you write func2d and inX by reference, which become dangling links when funcYgivenX .

Change the function to capture by value.

 std::function< std::function< double(double) >(std::function< double(double, double) >, double) > funcYgivenX = [](std::function< double(double, double) > func2d, double inX) { return [func2d, inX]( double inY ){ return func2d(inX, inY); }; }; 

When you use

 return [func2d, inX]( double inY ){ return func2d(inX, inY); }; 

you write the func2d and inX by value, which remain valid even after the funcYgivenX function funcYgivenX .

This is why the second version works, and the first version leads to undefined behavior.

See working code: http://ideone.com/X1CRGC .

+1
source

All Articles