Transformer une fonction std :: à deux variables en une variable à une variable

J’ai une fonction qui obtient deux valeurs, x et y, et renvoie le résultat:

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

Maintenant, je veux obtenir une fonction à variable unique pour une constante y. J’ai écrit le code suivant, mais cela ne fonctionne pas.

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

Qu’est-ce que je fais mal ici? Et quel est le meilleur moyen (le plus efficace) de le faire?

En C ++ 11, std::bind est essentiellement obsolète avec l’introduction de lambdas . Voici un exemple de liaison utilisant un 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 } 

Pour référence concernant la préférence de lambdas par rapport à std::bind on peut lire Effective Modern C ++ de Scott Meyers, article 32. En C ++ 11, il est impossible de déplacer la capture avec un lambda, et ce comportement ne peut être imité avec std::bind . Avec l'introduction de la capture initiale pour les lambdas en C ++ 14, même ce cas d'angle peut être résolu avec lambdas.

Non non Non. C’est pour std::bind que std::bind existe!

 #include  #include  #include  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's 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

Tout ce que vous faites est de fournir la fonction, puis les arguments que vous voulez fournir à la nouvelle fonction en tant qu'arguments secondaires à std::bind , et remplacez tous les "espaces vides" par `std :: placeholders :: _ X", où X est le n-ème nombre d'arguments, à partir de 1 pour le premier argument.

Vous pouvez même mettre en place des fermetures!

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

 #include  #include  #include  #include  int add(int a, int b) {return a + b;} int main() { std::vector> 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; } 

Si vous le souhaitez, vous pouvez également utiliser lambdas; ils ont aussi tendance à être plus propres, et vous pouvez probablement éviter les types désagréables de std::bind :

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

 #include  #include  #include  #include  int add(int a, int b) {return a + b;} int main() { std::vector> 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; } 

Quand vous utilisez

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

vous capturez les variables func2d , et inX par référence, qui deviennent des références pendantes lorsque la fonction funcYgivenX retour.

Changez la fonction pour capturer par valeur à la place.

 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); }; }; 

Quand vous utilisez

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

vous capturez les variables func2d et inX par valeur, qui restnt valables même après le retour de la fonction funcYgivenX .

C’est pourquoi la deuxième version fonctionne alors que la première version entraîne un comportement indéfini.

Voir le code de travail sur: http://ideone.com/X1CRGC .