Comparaison fonctions/ foncteurs

Cet exemple utilise une version simplifiée de la fonction de mesure de temps présentée dans ../Sujets/AuSecours/Mesurer-le-temps.html et compile avec C++ 20 (ce n'est pas essentiel, mais ça simplifie l'écriture).

#include <iostream>
#include <chrono>
#include <cmath>
#include <algorithm>
#include <vector>
#include <random>
#include <type_traits>
#include <utility>
using namespace std;
using namespace std::chrono;

template <class F, class ... Args>
   auto test(F f, Args &&... args) {
      auto pre = high_resolution_clock::now();
      auto res = f(std::forward<Args>(args)...);
      auto post = high_resolution_clock::now();
      return pair{ res, post - pre };
   }

double racine_fonction(double x) {
   return sqrt(x);
}
struct racine_foncteur {
   double operator()(double x) const {
      return sqrt(x);
   }
};

int main() {
   enum { N = 50'000'000 };
   vector<double> v(N);
   random_device rd;
   mt19937 prng{ rd() };
   uniform_real_distribution<> distrib; // 0.0 .. 1.0
   clog.rdbuf(nullptr);
   generate(begin(v), end(v), [&]() { return distrib(prng); });
   cout << "Test sur des fonctions..." << flush;
   auto [r0,dt0] = test([v]() mutable {
      transform(begin(v), end(v), begin(v), racine_fonction);
      return v.back();
   });
   cout << "Temps ecoule : "
        << duration_cast<milliseconds>(dt0) << '\n';
   cout << "Test sur des foncteurs..." << flush;
   auto [r1,dt1] = test([v]() mutable {
      transform(begin(v), end(v), begin(v), racine_foncteur{});
      return v.back();
   });
   cout << "Temps ecoule : "
        << duration_cast<milliseconds>(dt1) << '\n';
   // « effet de bord » pour empêcher l'elimination des calculs
   clog << r0 << ' ' << r1;
}

Quelques résultats suivent. Portez attention aux temps relatifs pour un même compilateur, mais ne comparez pas les compilateurs entre eux, car les exécutions sont faites sur des machines distinctes (note : le code que vous trouverez sur ces liens est la version C++ 17 de celui montré plus haut, mais les seules différences tiennent à l'affichage du temps écoulé) :

Wandbox (lien) Coliru (lien) Visual Studio 2019 (Release, 32 bits)
Test sur des fonctions...
- temps ecoule : 504 ms.
Test sur des foncteurs...
- temps ecoule : 498 ms.
Test sur des fonctions...
- temps ecoule : 207 ms.
Test sur des foncteurs...
- temps ecoule : 207 ms.
Test sur des fonctions...
- temps ecoule : 251 ms.
Test sur des foncteurs...
- temps ecoule : 148 ms.

En pratique, l'enjeu ici est qu'un bon optimiseur pourra souvent réaliser des optimisations semblables avec des fonctions et avec des foncteurs, mais à code exécuté équivalent il est probable que le recours à un foncteur plutôt qu'à une fonction ne soit pas un désavantage. L'enjeu est la capacité pour un compilateur de réaliser un function inlining : dans un contexte de programmation générique, offrir plus d'information au compilateur quant aux types impliqués accroît ses capacités de remplacer le code appelant par le code appelé.


Valid XHTML 1.0 Transitional

CSS Valide !