rappel vs lambda

Supposons que j'ai le code suivant que je souhaite refactoriser:

int toFuture()
{
  precalc();
  int calc = 5 * foobar_x() + 3;
  postcalc();
  return calc;
}

int toPast()
{
  precalc();
  int calc = 5 * foobar_y() - 9;
  postcalc();
  return calc;
}

Dans classic-C, Je refactoriserais ce code dans un worker () qui accepte un pointeur de fonction qui fait le calcul: code commun dans worker (), code spécifique fourni par le pointeur de fonction.

Avec C++11, devrais-je utiliser un lambda à la place? Si oui, comment l'implémenterais-je, dans ce cas?

Edit: il m'a juste traversé l'esprit qu'un modèle peut également fonctionner. Comment comparer une implémentation de modèle contre les deux autres?

26
demandé sur ildjarn 2011-10-20 01:54:12

4 réponses

Une approche:

template<typename CalcFuncT>
int perform_calc(CalcFuncT&& calcfunc)
{
    precalc();
    int const calc = std::forward<CalcFuncT>(calcfunc)();
    postcalc();
    return calc;
}

int main()
{
    perform_calc([]{ return 5 * foobar_x() + 3; }); // toFuture
    perform_calc([]{ return 5 * foobar_y() - 9; }); // toPast
}
40
répondu ildjarn 2012-03-14 21:06:25

Si vous voulez une approche de modèle utilisant des fonctionnalités C++11, cela pourrait sembler aussi simple que:

template<typename FuncType>
auto calculation(FuncType&& func) -> decltype(func())
{
    precalc();
    auto ret = func();
    postcalc();
    return ret;
}

Vous appelleriez simplement votre Fonction calculation et lui transmettriez soit un lambda, un foncteur, soit un pointeur de fonction. Votre seule difficulté dans ce cas serait si vous passiez une fonction qui avait un type de retour void... dans ce cas, vous obtiendrez une erreur de compilation (ce qui est une bonne chose contre une erreur d'exécution).

22
répondu Jason 2011-10-20 02:33:53

Je dirais que vous refactorisez du mauvais côté:

struct CalcGuard {
  CalcGuard() { /* replaces precalc() */ }
  ~CalcGuard() { /* replaces postcalc() */ }
};

int toFuture()
{
  return CalcGuard(), calc = 5 * foobar_x() + 3;
}

int toPast()
{
  return CalcGuard(), calc = 5 * foobar_y() - 9;
}
7
répondu MSalters 2011-10-20 08:31:32

Il est un C/C++ façon de le faire, et un C++11 chemin. Aucune façon implique lambdas ou des modèles.

La manière C/C++:

double MyFunc (int x, float y) { return x + y ; }

int main()
  {
  double (*pf) (int, float) ;
  pf = MyFunc ;
  pf (101, 202.0) ;
  }

La manière C++11:

#include <functional>

double MyFunc (int x, float y) { return x + y ; }

int main()
  {
  std::function<double (int, float)> f ;
  f = MyFunc ;
  f (51, 52.0) ;
  }

Dans les deux cas, vous passez simplement pf ou f à votre fonction refactorisée en tant que paramètre. L'utilisation de lambdas ou de modèles est exagérée ici.

1
répondu TonyK 2011-10-19 22:20:24