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

C++ Discussion :

choix d'une fonction en argument : lambda, class ou structure ? #optimisation


Sujet :

C++

  1. #21
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Ceci étant dit, si tu travailles sur base d'une énumération (reprenons l'idée des seules fonction trigono, par facilité) proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    enum WichFunction{
        sinus,
        cosinus,
        tangeante,
        /* ...*/
        MAX // TRES important, tu verras pourquoi ensuite
    };
    Le fait de travailler avec une classe prenant, pour la cause, une forme proche de
    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
    class Algo{
        /* je suis un gros fade, j'ai horreur de me répéter sur des noms de type trop complexes */
        using tab_t = std::vector<double (*) (double>;
        /* quitte à ne pas respecter l'OCP, respectons le SRP */
        static tab_t const & allFunctions(){
            static const tab_t funcs{&std::sin
                                            &std::cos,
                                            &std::tan /*,
                                            ... */};
            /* on se permet d'engueuler l'implémenteur si le nombre de fonctions indiquées
             * ne correspond pas au nombre de valeur énumérées
             */
            assert(funcs.size() == MAX &&  "Implementor!!! Please do your job !!!");
            return funcs;
        }
    public:
        /* chaque fois que l'on veut utiliser l'algorithme, il faut préciser la fonction qui sera utilisée */
        Algo(WichFunction f):f_{f}{
            /* L'utilisateur est un imbécile distrait qui pourrait nous servir un
                 Algo bad(static_cast<WichFunction>(127);
             */
           assert(f< MAX && "bad function requested");
        }
        double exec(double d) const{
           return allFunctions()[f_](d);     
        }
    }
    Alors, je sens que tu vas m'objecter que c'est sensiblement la même chose que d'avoir un switch, qu'il soit dans le constructeur ou dans la fonction... Sauf que :
    1- D'un point de vue conceptuel, on se rajoute un garde fous: on ne peut pas ajouter une valeur énumérée (avant MAX, ca va de soi) ou une fonction sans rajouter son pendant de "l'autre coté".

    J'aurais, bien sur, préféré une erreur de compilation, à ce sujet, ce qui devrait être possible, vu que les valeurs énumérés sont des constantes de compilation, mais, si tu oublies l'un des deux, le premier test qui utilisera Algo te rappellera à l'ordre

    Bien sur, tu pourrais demander au compilateur de te lancer un avertissement sur les valeurs énumérées absentes de ton switch... case, mais, qui s'en inquièterait

    2- Sans préjuger le moins du monde des optimisations que peut faire le compilateur sur un switch ... case, l'utilisation d'un tableau limite l'action à ... un décallage d'adresse dans le tableau, sans test pour savoir quelle valeur nous intéresse.

    Toi qui veut des performances, tu sera servi, car à ce titre, tu ne trouveras sans doute pas mieux (même si un bench correct est nécessaire pour confirmer cette assertion )

    3- Quitte à ne pas respecter l'OCP (car je peux admettre que ce ne soit pas toujours possible), je limite au maximum la protée de ce non respect.

    J'aurais d'ailleurs pu en faire une fonction libre qui ne soit pas déclarée dans le header, et qui serait juste présente dans le fichier d'implémentation, mais j'aurais perdu les possibilités d'inlining
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  2. #22
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Points : 16 213
    Points
    16 213
    Par défaut
    Citation Envoyé par Matthieu76 Voir le message

    Merci beaucoup même si je ne comprends pas trop cette ligne de code même si je sais ce qu'est basique un template mais un template de classe alors que c'est une fonction qui varie, pas une classe, je ne comprends pas tout... (J'irais voir plus tard sur internet)
    Qu'est-ce qu'une fonction ? Un truc que l'on peut appeler en mettant des parenthèses derrière avec des paramètres, et qui peut retourner une valeur.

    Dans ce code, a est-il une fonction ?

    On pourrait penser que oui, et ça pourrait être vrai. Mais pas forcément. a peut aussi être un objet :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    class A 
    {
      int operator()(int i, string const &s) { return 42; }
    }; 
     
    void f()
    {
      A a;
      int i = a(2, "Test");
    }
    On nomme généralement foncteur tout ce qui peut être appelé (une fonction, un pointeur de fonction, un std::function (qui d'ailleurs n'est pas fait pour être manipulé par pointeur, mais directement, pour reprendre un autre point), une instance d'une classe ayant redéfini l'opérateur(), une lambda (qui est un cas particulier d'une instance de classe ayant redéfini l'opérateur()).

    Et quand j'écris :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    template<class Function>
    int f(int i, Function fct) {return fct(2*i); }
    Je dis que ma fonction est paramétrée par un foncteur (qui peut être une classe ou pas, ici le mot clef class est sans signification, j'aurais pu écrire template<typename Function>). L'avantage est que si j’appelle f en lui passant une instance de classe, le code de l'opérateur() de cette classe est directement accessible quand on instancie le template, et c'est appel de fonction pourra être totalement inliné, chose bien moins facile pour le compilateur s'il manipule des pointeurs de fonction (y compris à l'aide de std::function).
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  3. #23
    Membre éclairé Avatar de Matthieu76
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Mars 2013
    Messages
    568
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2013
    Messages : 568
    Points : 890
    Points
    890
    Par défaut
    Citation Envoyé par JolyLoic Voir le message
    le code de l'opérateur() de cette classe
    L'opérateur() pour une classe est son constructeur, non ?

  4. #24
    Expert éminent
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Décembre 2015
    Messages
    1 565
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Décembre 2015
    Messages : 1 565
    Points : 7 648
    Points
    7 648
    Par défaut
    Citation Envoyé par Matthieu76 Voir le message
    L'opérateur() pour une classe est son constructeur, non ?
    Non, absolument pas.
    Le constructeur est utilisé au moment de la création de l'instance. L'opérateur() permet à l'instance d'être utilisée comme si c'était une fonction. Par exemple les lambda sont en fait des objets qui ont un opérateur().
    Tous les objets qui ont au moins un operateur() sont appelés foncteurs.
    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
    class UnLambda {
       int  x_;
    public:
       UnLambda( int x ) : x_(x) {}       // Un constructeur
       int operator()( int y )const {   // Un opérateur fonction
          return x_ + y;
       }   
    };
     
    int   x = 5;
    UnLambda  lb{ x };
    std::cout << lb(4);   // l'objet est utilisé comme une fonction ===> 9
     
    // ou bien il est totalement équivalent de faire
     
    int   x = 5;
    auto  lb = [=x]( int y ) { return x + y; }    // défini l'objet, et le construit
    std::cout << lb(4);   //       ===> 9

  5. #25
    Membre éclairé Avatar de Matthieu76
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Mars 2013
    Messages
    568
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2013
    Messages : 568
    Points : 890
    Points
    890
    Par défaut
    Du coup, je fais un truc de genre ?
    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
     
    class TrigonometricFunction 
    {
        int operator()(float x) = 0;
    }; 
     
    class Cosinus : TrigonometricFunction 
    {
        int operator()(float x) { return cos(x); };
    };
     
    class Sinus: TrigonometricFunction 
    {
        int operator()(float x) { return sin(x); };
    };
     
    class Tangent: TrigonometricFunction 
    {
        int operator()(float x) { return tan(x); };
    };
     
    class ListFunction()
    {
        Enum myEnum {cos = 0, sin, tan}; 
        vector<*TrigonometricFunction> list { new Cosinus(), new Sinus(), new Tangent() };
    }
     
    class Algo
    {
        private:
            TrigonometricFunction *TrigoFunction;
     
        public:
            Algo(ListFunction::myEnum e)
            {
                TrigoFunction = ListFunction::list[e];
            }
    }
    En c'est pas plus long à exécuter que des pointeurs sur fonction ?

    Et donc vous confirmez, je pars sur ça ?

  6. #26
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 115
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 967
    Points
    32 967
    Billets dans le blog
    4
    Par défaut
    Pourquoi garder un switch et un choix de l'algo à l'exécution ? Comptes-tu vraiment changer d'algo en cours d'exécution ?
    Pourquoi ne pas choisir l'algo à la compilation ce qui permettrait au compilo d'optimiser tout au maximum ? cf les posts de JolyLoic et mon idée initiale.
    Si l'opérateur n'est pas virtuel il ne sera pas choisi avec le typage dynamique mais du typage statique. C'est une fonction comme les autres.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  7. #27
    Membre éclairé Avatar de Matthieu76
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Mars 2013
    Messages
    568
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2013
    Messages : 568
    Points : 890
    Points
    890
    Par défaut
    Bousk, je ne veux pas que l'utilisateur définisse une fonction en paramètre mais choisisse parmi une enum donc l'idée JolyLoic ne me convient pas. Et pour ce qui est du switch, ne ne le veut pas à l'intérieur de ma fonction car cela ralentirait fortement mon algorithme et de plus ce n'est pas très beau niveau conception.

    Pourquoi la solution que je propose ne te convient pas ? Si tu ne m'explique pas, cela ne m'aide pas à grand-chose.

  8. #28
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 115
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 967
    Points
    32 967
    Billets dans le blog
    4
    Par défaut
    Citation Envoyé par Matthieu76 Voir le message
    Bousk, je ne veux pas que l'utilisateur définisse une fonction en paramètre mais choisisse parmi une enum donc l'idée JolyLoic ne me convient pas.
    Tu cries après des perfs dès le début et tu rejettes la solution qui a le plus de sens à ce sujet... Qui a dit que l'enum était obligatoirement lié à un switch runtime ?

    Un truc comme
    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
    template<class Func>
    struct BaseAlgo {
    	void call(float a) { Func::call(a); }
    };
     
    struct MyCos {
    	static void call(float a) { std::cout << std::cos(a) << std::endl; }
    };
    struct MySin {
    	static void call(float a) { std::cout << std::sin(a) << std::endl; }
    };
     
    enum class EnumParceQueCestMieux { Cos, Sin, };
    using AllAlgos = std::tuple<MyCos, MySin>;
     
    template<EnumParceQueCestMieux ALGO>
    struct EnChoisissantParmiUnEnumCestPlusJoli {
    	using Algo = typename std::tuple_element<static_cast<unsigned int>(ALGO), AllAlgos>::type;
    };
     
    template<EnumParceQueCestMieux ALGO>
    struct Algo : BaseAlgo<typename EnChoisissantParmiUnEnumCestPlusJoli<ALGO>::Algo> {
    };
     
    int main(int argc, char *argv[])
    {
    	BaseAlgo<MyCos>().call(3.0);
    	auto pp = Algo<EnumParceQueCestMieux::Cos>();
    	pp.call(3.0);
    	return 0;
    }
    Tu as même un choix parmi un enum puisque tu y tiens tant. A la compilation.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  9. #29
    Membre éclairé Avatar de Matthieu76
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Mars 2013
    Messages
    568
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2013
    Messages : 568
    Points : 890
    Points
    890
    Par défaut
    Ca revient au même que ce que j'ai proposé sauf que ça :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    int main(int argc, char *argv[])
    {
    	BaseAlgo<MyCos>().call(3.0);
    	auto pp = Algo<EnumParceQueCestMieux::Cos>();
    	pp.call(3.0);
    	return 0;
    }
    C'est 1 000 fois plus moche et moins clair que ça :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    int main(int argc, char *argv[])
    {
    	Algo myAlgo(cos);
    	myAlgo.call(3.0); // pour garder les même nom que dans ton exemple
    	return 0;
    }
    En encore une fois, ça change quoi que je passe par des templates ou par des classes ? Et tu ne m'as toujours pas expliqué en quoi ta solution était meilleure que la mienne.

  10. #30
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Citation Envoyé par Matthieu76 Voir le message
    En encore une fois, ça change quoi que je passe par des templates ou par des classes ?
    L'énorme avantage des template, c'est que tout le travail est fait à la compilation, et que, du coup, le compilateur pourra t'engueuler (au moment de la compilation !!!) si, pour une raison ou une autre, tu fourni un paramètre template qui ne correspond pas à ce qui est attendu.

    Tu auras donc une détection d'erreur bien plus tôt dans ton processus, et, de ce fait, tu sauras la corriger beaucoup plus facilement (enfin, une fois que tu te sera habitué à la diatribe du compilateur lorsqu'il travaille avec des template).

    Car il faut savoir que, plus une erreur est diagnostiquée tôt, plus il est facile de la situer et de la corriger (car, le diagnostique se rapproche forcément du moment où tu as écrit le cod ), et que le mieux est, effectivement, de s'aider du compilateur, car, a priori, tu tenteras une compilation de tes fichiers... directement après les avoir écrits (et donc, à un moment où le code qu'il contient est encore frais dans ton esprit )
    Et tu ne m'as toujours pas expliqué en quoi ta solution était meilleure que la mienne.
    Ben, justement, pour la raison que je viens d'expliquer
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  11. #31
    Membre éclairé Avatar de Matthieu76
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Mars 2013
    Messages
    568
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2013
    Messages : 568
    Points : 890
    Points
    890
    Par défaut
    Dans ce cas autant utiliser des templates partout au lieu de classe ??? Ça n'as pas de sens !

    En plus :
    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
    template<class Func>
    struct BaseAlgo {
    	void call(float a) { Func::call(a); }
    };
     
    struct MyCos {
    	static void call(float a) { std::cout << std::cos(a) << std::endl; }
    };
    struct MySin {
    	static void call(float a) { std::cout << std::sin(a) << std::endl; }
    };
     
    enum class EnumParceQueCestMieux { Cos, Sin, };
    using AllAlgos = std::tuple<MyCos, MySin>;
     
    template<EnumParceQueCestMieux ALGO>
    struct EnChoisissantParmiUnEnumCestPlusJoli {
    	using Algo = typename std::tuple_element<static_cast<unsigned int>(ALGO), AllAlgos>::type;
    };
     
    template<EnumParceQueCestMieux ALGO>
    struct Algo : BaseAlgo<typename EnChoisissantParmiUnEnumCestPlusJoli<ALGO>::Algo> {
    };
     
    int main(int argc, char *argv[])
    {
    	BaseAlgo<MyCos>().call(3.0);
    	auto pp = Algo<EnumParceQueCestMieux::Cos>();
    	pp.call(3.0);
    	return 0;
    }
    Ce code est moche est imbitable, on comprend rien... Ma solution est beaucoup plus clair et plus simple, elle est mieux.

  12. #32
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 115
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 967
    Points
    32 967
    Billets dans le blog
    4
    Par défaut
    Tu ne comprends rien. Pourtant ça reste du C++, et pas du plus velu.
    On t'explique depuis 1 semaine que ce serait mieux mais t'es entêté à garder ton truc parce que tu estimes que c'est plus joli, plus clair et mieux. Arguments que je trouve vraiment étrange, mais bon, je suppose qu'un code joli et subjectivement mieux c'est une forme d'optimisation ?
    Fais-toi plaisir, utilise ce que bon te semble après tout ça m'en touche une sans bouger l'autre.
    Inutile de venir ici le ressasser pour t'en convaincre.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  13. #33
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Citation Envoyé par Matthieu76 Voir le message
    Dans ce cas autant utiliser des templates partout au lieu de classe ??? Ça n'as pas de sens !
    On ne dit pas de le faire *** partout ***, on dit juste de le faire *** partout où il est possible de le faire ***. Nuance

    Il faut comprendre que, lorsque tu pars sur l'utilisation de fonctions virtuelles, et pour autant que ton code soit compris par le compilateur, tu dois attendre l'exécution de ton programme pour te rendre compte des éventuels problèmes posés par ton code.

    C'est d'ailleurs la raison pour laquelle on bassine les gens avec l'intérêt de mettre une politique stricte de tests unitaires en place : parce que, plus une erreur est repérée tôt, plus tu auras facile à la corriger.

    Mettons que tu aies un projet important, pour lequel tu dois ajouter une fonctionnalité, et qui nécessite de modifier une partie du code existant.

    Une fois que tu as fait ta modification, si l'un des tests unitaires échoue (alors qu'il n'échouait pas avant la modification), tu sais que c'est ta modification qui est la cause de cet échec, et, comme tu viens d'apporter cette modification (avec un peu de chance, les fichiers que tu as modifiés sont même encore ouverts dans ton EDI), tu auras forcément "facile" à corriger le problème.

    Par contre, si tu n'as pas de tests unitaires (ou si, pas de bol, tu n'en a pas qui touchent à la modification apportée), tu ne seras tenu au courant du problème que suite à ... un rapport de bug.

    Le truc, c'est qu'il peut falloir trois mois, six mois ou un an avant que ce rapport de bug n'arrive, et que, comme tu auras continué à travailler entre temps, tu auras eu "tout le temps" d'oublier les détails de ce que tu auras fait. Et pire encore: tu risques d'avoir basé certaines évolutions ultérieures sur les comportements "fautifs".

    C'est la raison pour laquelle la correction de bugs est si compliquée: on ne sait "plus trop" ce que l'on a modifié, ni pourquoi, et, surtout, les correctifs apportés risquent (car ce n'est -- par chance -- pas toujours le cas) de "casser" le code à d'autres endroits.

    Seulement, si tu as cinq fonctions à mettre au point pour pouvoir ajouter une fonctionnalité, tu ne vas sans doute pas lancer toute la batterie de tests (qui peut parfois demander des plombes à s'effectuer) à chaque fois que tu as fini de travailler sur l'une de ces fonctions! tu vas sans doute attendre d'avoir... intégré ta nouvelle fonctionnalité, et d'être arrivé à compiler l'ensemble avant d'exécuter "tous les tests d'un seul coup".

    Hé bien, il faut te dire que, si les tests te facilitent la vie, car ils te permettent de corriger les problèmes "plus tôt" que si tu avais du attendre un rapport de bug, la compilation en elle-même peut te permettre de repérer des erreurs encore plus tôt que les tests unitaires. Et qu'elle peut donc te faciliter encore d'autant plus la vie en apportant des solutions au problème encore plus tôt.

    Car, si on peut s'attendre à ce que tu ne lance la batterie de tests unitaires qu'une fois "la nouvelle fonctionnalité développée", on peut malgré tout aussi s'attendre à ce que... tu lances une compilation (ne serait-ce que de chaque fichier que tu modifies)... dés que tu as fini la modification d'une fonction (entre autres, pour t'assurer que tu n'a pas fait de "stupides erreurs de syntaxe", comme oublier le ; final).

    Le truc, c'est que le compilateur ne va pas se contenter de s'assurer que tu utilises la syntaxe appropriée: si tu lui cause correctement, il peut également s'assurer que toute une série de contrats qui seront passés entre toi (le développeur) et l'utilisateur (c'est peut-être aussi toi ) seront respectés scrupuleusement.

    C'est ce qui fait que la programmation générique est d'une telle puissance en C++; car, si un contrat n'est pas respecté, le compilateur (sur lequel tu peux compter pour ne rien laisser passer) t'engueulera comme du poisson pourri et refusera de générer l'exécutable final.

    Alors, nous sommes bien d'accord sur deux points: la programmation générique n'est pas la panacée, "le remède à tous les maux"; et la programmation générique est souvent complexe, ou, à tout le moins, sans doute plus complexe que la programmation orientée objets.

    Mais un fait demeure: elle peut te simplifier énormément la vie aussi bien en termes de quantité de code à écrire (car tu peux observer un comportement identique pour plusieurs types de données) qu'en termes de détection d'erreur(même si les messages d'erreurs deviennent d'autant plus cryptiques ).

    Dés lors, même si nous sommes bien d'accord sur le fait qu'il ne faut pas l'utiliser de manière systématique, pour n'importe quel type de problème, et que c'est d'autant plus vrai que certains problèmes se géreront bien plus facilement en utilisant d'autres paradigmes (comme l'orienté objet), il faut malgré tout se dire que, si on a le choix du paradigme, et que si le paradigme générique est "l'un des paradigmes possibles", on a -- très vraisemblablement -- le plus grand intérêt à le préférer à tout autre.

    Ce code est moche est imbitable, on comprend rien...
    j'aurais tendance à dire que ce code te parait imbitable:
    1. parce que tu n'a pas (encore) l'habitude du paradigme générique et
    2. parce que les noms choisis ne sont pas forcément les plus clairs (entre autres: EnumParceQueCestMieux ou EnChoisissantParmiUnEnumCestPlusJoli

    et que
    Ma solution est beaucoup plus clair et plus simple, elle est mieux.
    Elle est sans doute plus claire (pour l'instant) pour toi, mais, de là à dire "elle est mieux", il y a un pas que l'on est loin de franchir aisément.
    • parce que la virtualité des fonctions, c'est un processus qui prend du temps
    • parce que la détection d'erreurs est reportées "au callendes grèques"
    • parce que la programmation générique a un certain charme
    • pour plein d'autres raisons que je ne mettrai pas ici
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

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

Discussions similaires

  1. [AS2] Atteindre attribut d'une classe depuis une fonction interne a la classe
    Par Demco dans le forum ActionScript 1 & ActionScript 2
    Réponses: 6
    Dernier message: 18/04/2006, 21h03
  2. Comment passer une fonction en argument
    Par Pades75 dans le forum Langage
    Réponses: 4
    Dernier message: 16/02/2006, 10h34
  3. Signature d'une fonction sans argument
    Par cj227854 dans le forum C++
    Réponses: 5
    Dernier message: 20/10/2005, 17h01
  4. creer une fonction avec arguments
    Par niglo dans le forum ASP
    Réponses: 3
    Dernier message: 03/06/2005, 08h04
  5. Passer une fonction comme argument à une fonction
    Par Cocotier974 dans le forum Général Python
    Réponses: 4
    Dernier message: 29/06/2004, 13h41

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