IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage C++ Discussion :

Template de pointeur sur fonction (presque) générique


Sujet :

Langage C++

  1. #21
    Membre éclairé

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2007
    Messages
    373
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Santé

    Informations forums :
    Inscription : Juin 2007
    Messages : 373
    Points : 765
    Points
    765
    Par défaut
    J'ai effectivement déjà pensé à ça, et c'est une des meilleures alternatives.
    En revanche, j'y vois deux inconvénients qui me font préférer d'utiliser ma macro :
    1. Ça nécessite de spécifier le type dans la déclaration de la variable, puis la fonction de comparaison dans le constructeur. Ces deux étapes étant bien souvent écrites dans deux fichiers différents, la maintenance s'en retrouve un peu plus lourde.
    2. Avec le pointeur en paramètre template, j'imagine qu'il est possible d'optimiser plus facilement le code que si le pointeur est une variable membre du foncteur. Un petit benchmark (g++ -std=c++0x -O3) :
      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      64
      65
      66
      67
      68
      69
      70
      71
      72
      73
      74
      75
      76
      77
      78
      79
      80
      81
      82
      83
      84
      #include <iostream>
      #include <string>
      #include <vector>
      #include <algorithm>
      #include <chrono>
      #include <random>
       
      // Version pointeur template
      template<typename T, typename I, I (T::*F)() const>
      struct mem_fun_comp_ {
          bool operator () (const T& t1, const T& t2) const {
              return (t1.*F)() < (t2.*F)();
          }
      };
       
      template<typename T, typename I>
      T mem_fun_owner(I (T::*f)() const) { return std::declval<T>(); }
       
      template<typename T, typename I>
      I mem_fun_return_type(I (T::*f)() const) { return std::declval<I>(); }
       
      #define mem_fun_comp(f) mem_fun_comp_<decltype(mem_fun_owner(f)), decltype(mem_fun_return_type(f)), f>
       
      // Version pointeur membre
      template<typename T, typename I>
      struct mem_fun_comp_koala {
          using F = I (T::*)() const;
          const F func;
       
          mem_fun_comp_koala(F f) : func(f) {}
       
          bool operator () (const T& t1, const T& t2) const {
              return (t1.*func)() < (t2.*func)();
          }
      };
       
      // Donnée à trier
      struct test {
          std::size_t id_;
          std::size_t id() const { return id_; }
      };
       
      int main(int argc, char* argv[]) {
          std::vector<test> ov;
       
          // On génère un vecteur avec 1e6 valeurs aléatoires
          std::default_random_engine                 gen;
          std::uniform_int_distribution<std::size_t> distrib;
       
          const std::size_t num = 1000000;
          for (std::size_t i = 0; i < num; ++i) {
              ov.push_back({distrib(gen)});
          }
       
          // On trie plusieurs fois ce même vecteur...
       
          // ... avec le pointeur template
          for (std::size_t i = 0; i < 5; ++i) {
              auto start = std::chrono::high_resolution_clock::now();
       
              auto v = ov;
              std::sort(v.begin(), v.end(), mem_fun_comp(&test::id)());
       
              auto end = std::chrono::high_resolution_clock::now();
              auto elapsed = end - start;
              std::cout << elapsed.count() << std::endl;
          }
       
          std::cout << std::endl;
       
          // ... avec le pointeur membre
          for (std::size_t i = 0; i < 5; ++i) {
              auto start = std::chrono::high_resolution_clock::now();
       
              auto v = ov;
              std::sort(v.begin(), v.end(), mem_fun_comp_koala<test, std::size_t>(&test::id));
       
              auto end = std::chrono::high_resolution_clock::now();
              auto elapsed = end - start;
              std::cout << elapsed.count() << std::endl;
          }
       
          return 0;
      }
      Sans optimisation, la version avec pointeur template prend ~10% de temps en moins, avec optimisation on grimpe à ~50% (j'ai été surpris). À noter que si on remplace le foncteur avec pointeur membre par une lambda, alors les performance sont égales (voir meilleures, allez savoir pourquoi) qu'avec le paramètre template. Après je connais la musique : dans mon cas c'est effectivement de l'optimisation prématurée, mais je pense que ça reste un argument important.


    Merci JolyLoic pour ce lien, j'aurais dû penser à regarder là bas... En tout cas je pense que ça répond à ma question initiale.

  2. #22
    En attente de confirmation mail

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2004
    Messages
    1 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France, Doubs (Franche Comté)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Points : 3 311
    Points
    3 311
    Par défaut
    Et tu as benché en écrivant une lambda à la place de ton truc ?

  3. #23
    Expert confirmé
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2012
    Messages
    1 711
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2012
    Messages : 1 711
    Points : 4 442
    Points
    4 442
    Par défaut
    Citation Envoyé par Kalith Voir le message
    Sans optimisation, la version avec pointeur template prend ~10% de temps en moins, avec optimisation on grimpe à ~50% (j'ai été surpris).
    A noter quand même qu'en reprenant ton code, mais en mettant la copie de vecteur en dehors du chrono, le temps d'exec est identique avec et sans opti (g++ 4.8).

    Du coup, l'opti ne touche que la copie de vector.

  4. #24
    Membre éclairé

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2007
    Messages
    373
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Santé

    Informations forums :
    Inscription : Juin 2007
    Messages : 373
    Points : 765
    Points
    765
    Par défaut
    Citation Envoyé par Flob90 Voir le message
    Et tu as benché en écrivant une lambda à la place de ton truc ?
    Oui, les performances sont aussi bonnes, comme je l'ai écrit dans mon message précédent (je l'ai édité quelques minutes après l'avoir envoyé). L'inconvénient de cette lambda est qu'on ne peut pas écrire quelque chose de générique et réutilisable partout, ce qui est le but initial.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    std::sort(v.begin(), v.end(), [](const test& t1, const test& t2) { return t1.id() < t2.id(); });
    Citation Envoyé par Iradrille Voir le message
    A noter quand même qu'en reprenant ton code, mais en mettant la copie de vecteur en dehors du chrono, le temps d'exec est identique avec et sans opti (g++ 4.8).
    Ben pas chez moi (g++ 4.7.2), les temps d'exécution ne sont pratiquement pas modifiés. Tu es sûr de ton coup?

  5. #25
    Expert confirmé
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2012
    Messages
    1 711
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2012
    Messages : 1 711
    Points : 4 442
    Points
    4 442
    Par défaut
    Citation Envoyé par Kalith Voir le message
    Ben pas chez moi (g++ 4.7.2), les temps d'exécution ne sont pratiquement pas modifiés. Tu es sûr de ton coup?
    Après vérification...
    g++-4.8 -std=c++11 main.cpp -o3 -o main
    -o3 au lieu de -O3

    Du coup je trouve la même chose que toi.

+ Répondre à la discussion
Cette discussion est résolue.
Page 2 sur 2 PremièrePremière 12

Discussions similaires

  1. Variadic template et pointeur sur fonction
    Par Invité dans le forum Langage
    Réponses: 5
    Dernier message: 14/02/2013, 20h57
  2. Réponses: 4
    Dernier message: 15/07/2011, 13h04
  3. pointeurs sur fonction en C++
    Par cemoi dans le forum C++
    Réponses: 7
    Dernier message: 29/11/2004, 13h19
  4. [langage] Pointeur sur fonction
    Par Fanch.g dans le forum Langage
    Réponses: 2
    Dernier message: 02/10/2004, 10h43
  5. Declaration de fonction retournant un pointeur sur fonction
    Par pseudokifaitladifférence dans le forum C
    Réponses: 5
    Dernier message: 11/08/2003, 19h37

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo