web-dev-qa-db-fra.com

À l'opposé de std :: bind, passez différentes fonctions pour des paramètres donnés

J'ai plusieurs fonctions avec des signatures presque identiques (beaucoup plus courtes que le code réel):

int hello(A a, B b, C c, int n);
int there(A a, B b, C c, int n);
int how(A a, B b, C c, int n);
int are(A a, B b, C c, int n);
...

Etc. Ensuite, lors de l'appel, le code crée les paramètres une fois, puis passe les mêmes objets à chaque fonction, sauf n:

A a; B b; C c;
hello(a, b, c, 240);
there(a, b, c, 33);
how(a, b, c, 54);
are(a, b, c, 67);

Ce que je voudrais réaliser est quelque chose de similaire à la façon dont std::bind est normalement utilisé, sauf que je voudrais échanger la fonction. par exemple:

auto uber_func = std::something_stack_overflow_recommends(..., a, b, c)
uber_func(hello, 240);
uber_func(there, 33);
uber_func(how, 54);
uber_func(are, 67);

Ce n'était pas clair pour moi d'après la documentation de std::bind s'il pouvait le faire. Avez-vous des suggestions?

13
jeanluc

Vous pouvez utiliser un Lambda, qui a fait std::bind pour la plupart obsolète, car il est plus facile à utiliser:

  auto uber_func = [&](std::function<int(A, B, C, int)> f, int n) {
    return f(a, b, c, n);
  };

  uber_func(hello, 240);
  uber_func(there, 33);
  uber_func(how, 54);
  uber_func(are, 67);

La première solution impose que toutes les fonctions aient la même interface bien connue. Si nécessaire, il pourrait être généralisé pour prendre en charge également différents types de fonctions:

  auto uber_func = [&](auto f, int n) {
    return f(a, b, c, n);
  };

La seconde solution est plus générale et évite la surcharge de performances de la première solution. Petit inconvénient: il nécessitera un compilateur C++ 14, alors que le premier devrait fonctionner sur n'importe quel compilateur C++ 11. Si ce n'est pas un problème, je préférerais la deuxième solution à la première.

J'ai réalisé que vous aviez demandé comment le faire avec std::bind et je n'ai pas répondu à cela. Cependant, puisque C++ 11 Lambdas a largement remplacé std::bind. Depuis C++ 14, c'est encore plus clair, car de nouvelles améliorations ont été ajoutées. À moins que la compatibilité avec C++ 98 ne soit une exigence stricte, je recommanderais de éviter std::bind en faveur de Lambdas .

11
Philipp Claßen

Vous pouvez construire un objet avec tous les paramètres sauf le dernier:

template<typename A, typename B, typename C>
struct uber
{
   A a;
   B b;
   C c;

   uber(A a, B b, C c) : a(a), b(b), c(c) {}

   template<typename F> 
   auto operator()(F f, int n) { f(a,b,c,n); }
};

puis utilisez l'opérateur d'appel basé sur un modèle pour appeler les fonctions individuelles:

A a; B b; C c;
auto uber_func = uber{a,b,c};
uber_func(hello, 240);
uber_func(there, 33);
uber_func(how, 54);
uber_func(are, 67);
3
cigien