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