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 :

ternaire et erreur bizarre


Sujet :

Langage C++

  1. #1
    Membre émérite
    Avatar de imperio
    Homme Profil pro
    Étudiant
    Inscrit en
    Mai 2010
    Messages
    852
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

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

    Informations forums :
    Inscription : Mai 2010
    Messages : 852
    Points : 2 298
    Points
    2 298
    Par défaut ternaire et erreur bizarre
    Bonjour,

    Ce n'est pas un problème rencontré mais plutôt une curiosité :

    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
    class A
    {
    public:
        A(){}
    };
     
    class B : public A
    {
    public:
        B() : A(){}
    };
     
    class C : public A
    {
    public:
         C() : A(){}
    };
     
    A *test(int i)
    {
        return (i ? (new B) : (new C));
    }
     
    int main()
    {
        test(0);
        return 0;
    }
    Avec MSVC2010 (je précise car avec mingw j'ai autre chose) il me dit :

    main.cpp: erreur : C2446: "pas de conversion de 'B *' en 'A *'. Les types points n'ont aucun rapport entre eux, conversion nécessitant reinterpret_cast, cast de style C ou cast de style fonction"
    Etrange non ? J'avais testé avec un autre compilateur hier et il m'avait sorti une même erreur. Après une petite recherche, les seules solutions que j'avais trouvé étaient de caster. Mais pourquoi ? En temps normal quand on renvoie quelque chose comme ça :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    A *test()
    {
      return new B;
    }
    ça fonctionne parfaitement. Bien que le problème n'en soit pas vraiment (il suffirait de faire un if else après tout), je suis curieux de comprendre d'où cela provient.

    Merci d'avance !

  2. #2
    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
    J'ai un message d'erreur légèrement différent du tien (pas de mention de A*), et qui correspond exactement à ce à quoi je m'attendais (VC++2012) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    testternarycast\source.cpp(21): error C2446: ':'*: pas de conversion de 'C *' en 'B *'
    Quel est le type de l'expression : i ? (new B) : (new C) ? Tu aimerais qu'elle soit de type A*, mais comment le compilateur le saurait-il ?

    En fait, si le type des deux valeurs possible est le même, pas de soucis, ça devient le type de l'expression. Mais ici, les deux valeurs possibles ont comme type B* et C*, deux types différents. Les règles sont alors plus complexes (voir la norme §5.16), je crois que la version simplifiée est que l'on essaye de caster l'un en l'autre, et réciproquement, afin de trouver un type commun aux deux. Ici, aucune conversion n'existe de l'un à l'autre (il faudrait passer vers un troisième type, A), donc la compilation échoue.

    Le code suivant compile :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    A *test(int i)
    {
        return (i ? (static_cast<A*>(new B)) : (new C));
    }
    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. #3
    Membre habitué
    Homme Profil pro
    Doctorant en Astrophysique
    Inscrit en
    Mars 2009
    Messages
    312
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Doctorant en Astrophysique
    Secteur : Enseignement

    Informations forums :
    Inscription : Mars 2009
    Messages : 312
    Points : 176
    Points
    176
    Par défaut
    Bonjour.

    Il est nécessaire de caster parce que l'opérateur ternaire ne peut qu'opérer sur des types semblables. En gros, si T et U sont des types, l'opérateur ternaire doit être de la forme :
    bool ? T : T et non bool ? T : U

    Par exemple si tu essayes cela,
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    return (i ? (static_cast<A*>(new B)) : (static_cast<A*>(new C)));
    ça marche

    EDIT:
    @JolyLoic: ah merci, je ne connaissais pas ces règles plus complexes dans le standard, du coup j'avais pris l'habitude de toujours caster manuellement vers le même type.

  4. #4
    Membre émérite
    Avatar de imperio
    Homme Profil pro
    Étudiant
    Inscrit en
    Mai 2010
    Messages
    852
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

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

    Informations forums :
    Inscription : Mai 2010
    Messages : 852
    Points : 2 298
    Points
    2 298
    Par défaut
    Je ne pensais pas qu'il faisait cette "vérification" supplémentaire. Je trouve ça légèrement étrange mais si c'est défini dans la norme on n'y peut rien. Je trouve ça juste un peu regrettable...

    Merci pour vos éclaircissements !

  5. #5
    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
    Salut,
    Citation Envoyé par imperio Voir le message
    Je ne pensais pas qu'il faisait cette "vérification" supplémentaire. Je trouve ça légèrement étrange mais si c'est défini dans la norme on n'y peut rien. Je trouve ça juste un peu regrettable...
    En fait, c'est normal...

    Ce qu'il faut savoir, c'est que contrairement à la fonction if(test), l'opérateur ternaire permet de créer des constantes de compilation.

    Pour que cela puisse fonctionner avec les constantes de compilation (donc, en dehors de tout contexte d'exécution dynamique!!!), il faut:
    1. que les types des deux opérandes soient identiques
    2. que le compilateur trouve dans le code toutes les informations qui lui permettront de fournir la constante demandée

    Or, B* (un pointeur sur un objet de type B) et C* (un pointeur sur un objet de type C) sont... deux types absolument différents, et ce, même s'ils ont une base commune.

    Tu remarqueras d'ailleurs que l'on a le même problème avec les classes template!

    Si tu écris une classe template du genre de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    template <typename T>
    struct Trait{
        typedef T * ptr_type; // en C++11 : using ptr_type = T* ;
        void foo( ptr_type value){
            /* ...*/
        }
    };
    les types Trait<A>, Trait<B> et Trait<C> sont trois types totalement différents et indépendants, et ce, même si tu peux effectivement passer un B* ou un C* à la spécialisation Trait<A>::foo.

    Ceci dit, le code exécutable généré par un code proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    A *test(int i)
    {
        return (i ? (static_cast<A*>(new B)) : (new C));
    }
    a de grandes chances d'être totalement identique au code exécutable généré par un code proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    A *test(int i)
    {
        if (i)
            return new B;
        return new C;
    }
    voire, même plutôt à un code proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    A  *test(int i)
    {
        A * temp;
        if (i)
            temp = new B;
        else
            temp =new C;
        return temp;
    }
    (Si tant est qu'il y ait effectivement une différence entre les deux, je n'ai pas vérifié au niveau de l'assembleur).

    Dés lors, je sais qu'il y a encore des boites qui préconise la règle de codage connue sous le nom de SESE (Single Entry, Single Exit), et l'on pourrait facilement relancer un débat au sujet de cette règle, mais, toutes choses étant égales, je préfèrerais l'un de ces deux codes (quitte à voir s'il y a bel et bien une différence au niveau de l'assembleur généré) à l'utilisation de l'opérateur ternaire, et ce, d'autant plus si, pour pouvoir utiliser l'opérateur ternaire, il faut passer par un static_cast.

    La raison est à mon sens toute simple:

    Je trouve, personnellement, que même lorsque l'on a l'habitude de l'utiliser, l'opérateur ternaire nécessite un effort de compréhension bien supérieur à celui que peut nécessiter la compréhension d'un simple if (... else) et que si l'on n'a pas le bénéfice d'une optimisation possible (comme c'est le cas dans cette situation), il est sans doute préférable de choisir la forme qui apportera la meilleure visibilité
    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

  6. #6
    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 : 33
    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
    Cette différence du ternaire par rapport à un if que tu viens d'expérimenter est tout simplement le fait que cette structure conditionnelle a un typage plus fort que la structure plus "classique" du if (en C++ du moins).

    C'est pour moi la seule raison qui fait que j'ai tendance à en utiliser : je sais que je vais faire une structure conditionnel ayant un type bien définie ? Alors j'utilise un ternaire pour que le compilateur m'indique si quelque chose ne va pas.

  7. #7
    Membre émérite
    Avatar de imperio
    Homme Profil pro
    Étudiant
    Inscrit en
    Mai 2010
    Messages
    852
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

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

    Informations forums :
    Inscription : Mai 2010
    Messages : 852
    Points : 2 298
    Points
    2 298
    Par défaut
    Citation Envoyé par koala01 Voir le message
    Dés lors, je sais qu'il y a encore des boites qui préconise la règle de codage connue sous le nom de SESE (Single Entry, Single Exit), et l'on pourrait facilement relancer un débat au sujet de cette règle, mais, toutes choses étant égales, je préfèrerais l'un de ces deux codes (quitte à voir s'il y a bel et bien une différence au niveau de l'assembleur généré) à l'utilisation de l'opérateur ternaire, et ce, d'autant plus si, pour pouvoir utiliser l'opérateur ternaire, il faut passer par un static_cast.

    La raison est à mon sens toute simple:

    Je trouve, personnellement, que même lorsque l'on a l'habitude de l'utiliser, l'opérateur ternaire nécessite un effort de compréhension bien supérieur à celui que peut nécessiter la compréhension d'un simple if (... else) et que si l'on n'a pas le bénéfice d'une optimisation possible (comme c'est le cas dans cette situation), il est sans doute préférable de choisir la forme qui apportera la meilleure visibilité
    Au debut je faisais des ternaires (en C surtout) car on m'avait dit que c'etait plus rapide a l'execution (je n'ai pas cherche a savoir si c'etait vrai, mais pour le coup je vais le faire car ca fait trop longtemps que cette question est en suspens). Maintenant c'est plutot pour raccourcir un peu mon code et le rendre plus lisible (au moins pour moi). Je prefere clairement ca :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    int func(int a, int b)
    {
      return (a > b ? a : b);
    }
    que :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    int func(int a, int b)
    {
      if (a > b)
        return a;
      return b;
    }
    J'ai plus l'habitude de voir le premier cas que le deuxieme donc j'ai fini par m'y faire. Apres chacun son truc.

    Tiens d'ailleurs le ternaire respecte le SESE si je comprends bien. Je ne comprends pas vraiment l'interet de cette regle de codage. Elle garantit en gros que la fonction s'executera jusqu'a la fin et qu'il n'y aura pas de return surprise mais elle oblige dans la majorite des cas a creer au moins une variable supplementaire pour contenir la valeur de retour. ''fin bref ! Fort etrange de mon point de vue mais ca doit sans doute avoir son interet !

    Citation Envoyé par koala01 Voir le message
    En fait, c'est normal...

    Ce qu'il faut savoir, c'est que contrairement à la fonction if(test), l'opérateur ternaire permet de créer des constantes de compilation.

    Pour que cela puisse fonctionner avec les constantes de compilation (donc, en dehors de tout contexte d'exécution dynamique!!!), il faut:
    que les types des deux opérandes soient identiques
    que le compilateur trouve dans le code toutes les informations qui lui permettront de fournir la constante demandée
    Or, B* (un pointeur sur un objet de type B) et C* (un pointeur sur un objet de type C) sont... deux types absolument différents, et ce, même s'ils ont une base commune.
    Je pense que je pense trop "C" encore. Prenons un exemple (tres) grossier : c'est un peu comme si on retournait un pointeur void* provenant d'un char* ou d'un int*. Pour illustrer mes propos :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    int *funcInt()
    {
      return malloc(sizeof(int));
    }
     
    char *funcChar()
    {
      return malloc(sizeof(char));
    }
     
    void *func(int i)
    {
      return (i ? funcInt() : funcChar());
    }
    Ce code passera comme une lettre a la poste en C mais son equivalent C++ n'appreciera pas. C'est a cause de cette logique que je ne reussissais pas a comprendre. "Puisqu'ils ont le meme parent, pourquoi je ne peux pas les mettre dans un ternaire ?". Encore des subtilites du C++ qu'il me faut apprendre.

    Citation Envoyé par Flob90
    Cette différence du ternaire par rapport à un if que tu viens d'expérimenter est tout simplement le fait que cette structure conditionnelle a un typage plus fort que la structure plus "classique" du if (en C++ du moins).

    C'est pour moi la seule raison qui fait que j'ai tendance à en utiliser : je sais que je vais faire une structure conditionnel ayant un type bien définie ? Alors j'utilise un ternaire pour que le compilateur m'indique si quelque chose ne va pas.
    Je ne pensais pas le ternaire complique a ce point ni meme qu'il pouvait servir a ca ! Pour moi ca se cantonnait a un if/else un peu plus rapide (faut vraiment que j'aille verifier cette info !). Finalement j'ai bien fait de faire ce sujet !

    Merci pour vos eclaircissements !

    EDIT: J'ai trouve sur ce sujet la preuve que je me faisais des illusions sur le ternaire. Ce n'est donc pas plus optimise qu'un if else ! Interessant en tout cas, je le recommande aux interesses.

  8. #8
    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 imperio Voir le message
    Au debut je faisais des ternaires (en C surtout) car on m'avait dit que c'etait plus rapide a l'execution (je n'ai pas cherche a savoir si c'etait vrai, mais pour le coup je vais le faire car ca fait trop longtemps que cette question est en suspens).
    En fait, il est possible que certaines optimisations soient apportées par le compilateur avec l'opérateur ternaire qui ne pourraient peut etre (et ce n'est meme plus sur, étant donné que les compilateurs sont de plus en plus "intelligents") pas être apportées avec le if ... else.

    L'équipe (enfin, une personne de l'équipe ) a récemment traduit une série d'articles sur l'étude du C++ bas niveau.

    Un petit détour par ces traductions pourrait sans doute t'en apprendre d'avantage (dont les articles qui parlent des conditions )
    Maintenant c'est plutot pour raccourcir un peu mon code et le rendre plus lisible (au moins pour moi). Je prefere clairement ca :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    int func(int a, int b)
    {
      return (a > b ? a : b);
    }
    que :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    int func(int a, int b)
    {
      if (a > b)
        return a;
      return b;
    }
    C'est justement l'un des rares cas dans lequel il peut effectivement être utile et intéressant, avec quelques autres cas vraiment particuliers dans certaines situations particulières.

    Mais, dans le cas qui nous intéresse, avec le transtypage qu'il impose, cela devient beaucoup moins lisible à mon sens

    Tiens d'ailleurs le ternaire respecte le SESE si je comprends bien.
    Il n'y a qu'un point d'accès (l'appel de la fonction elle-même) et un point de sortie (le return), donc oui, on a bien respecté SESE
    Je ne comprends pas vraiment l'interet de cette regle de codage.
    Je vais t'avouer honnêtement que, à l'heure actuelle, je ne comprend pas non plus l'intérêt de cette règle de codage.

    Cependant, il faut se rappeler que le génie logiciel informatique a maintenant près de 60 ou 70 ans, pendant lesquels il a eu largement l'occasion d'évoluer.

    Il est donc possible de trouver une justification "historique" à cette règle, dans les faits que:
    • certains langages n'autorisaient, à leurs débuts, pas d'avoir plusieurs points de sortie à une fonction
    • les méthodes de représentations d'algorithmes d'origine (flowchart en tête) étaient beaucoup plus lisibles en respectant cette règle

    Elle garantit en gros que la fonction s'executera jusqu'a la fin et qu'il n'y aura pas de return surprise mais elle oblige dans la majorite des cas a creer au moins une variable supplementaire pour contenir la valeur de retour. ''fin bref ! Fort etrange de mon point de vue mais ca doit sans doute avoir son interet !
    A vrai dire, je crois que ca doit clairement être évalué au coup par coup, mais je comprends d'autant plus ton point de vue que je considère aussi cette règle comme totalement absurde, actuellement du moins
    Je pense que je pense trop "C" encore. Prenons un exemple (tres) grossier : c'est un peu comme si on retournait un pointeur void* provenant d'un char* ou d'un int*. Pour illustrer mes propos :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    int *funcInt()
    {
      return malloc(sizeof(int));
    }
     
    char *funcChar()
    {
      return malloc(sizeof(char));
    }
     
    void *func(int i)
    {
      return (i ? funcInt() : funcChar());
    }
    oui, parce que tu as très peu de contrôle de type en C et que la taille d'un pointeur est de toutes manière fixe et définitive (pour une architecture donnée), quel que soit le type se trouvant à l'adresse maintenue par le pointeur.

    C++ tend cependant:
    à éviter au maximum le recours à un void * car on perd "toute information" au sujet de l'objet pointé
    à inciter très largement à l'utilisation du transtypage explicite, afin que l'on puisse plus facilement les retrouver dans le code

    Ce code passera comme une lettre a la poste en C mais son equivalent C++ n'appreciera pas. C'est a cause de cette logique que je ne reussissais pas a comprendre. "Puisqu'ils ont le meme parent, pourquoi je ne peux pas les mettre dans un ternaire ?". Encore des subtilites du C++ qu'il me faut apprendre.
    Je peux te rassurer sur ce point:

    Si on apprend les bases du C++ (la syntaxe, les mots clés, peut etre même l'utilisation de la bibliothèque standard) en quelques dizaines d'heures, il faut à tout le monde plusieurs années pour "en faire le tour".

    J'en fais personnellement depuis pas mal de temps, et je rencontre encore souvent des subtilités
    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

  9. #9
    Membre émérite
    Avatar de imperio
    Homme Profil pro
    Étudiant
    Inscrit en
    Mai 2010
    Messages
    852
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

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

    Informations forums :
    Inscription : Mai 2010
    Messages : 852
    Points : 2 298
    Points
    2 298
    Par défaut
    Citation Envoyé par koala01 Voir le message
    En fait, il est possible que certaines optimisations soient apportées par le compilateur avec l'opérateur ternaire qui ne pourraient peut etre (et ce n'est meme plus sur, étant donné que les compilateurs sont de plus en plus "intelligents") pas être apportées avec le if ... else.
    Je trouve l'evolution des compilateurs C / C++ vraiment impressionnante (je ne me suis pas vraiment penche sur ceux des autres langages). Pourvu que le progres ne s'arrete jamais !

    Le seul defaut c'est qu'on en perdrait presque de vue notre "objectif". Ou qu'on s'y perdrait tout court. Par exemple il m'a ete difficile de trouver directement dans le man de gcc certains flags de compilation particulier dont je pourrais avoir besoin (creer une lib dynamique par exemple). Apres ce n'est que mon point de vue.

    Citation Envoyé par koala01 Voir le message
    L'équipe (enfin, une personne de l'équipe ) a récemment traduit une série d'articles sur l'étude du C++ bas niveau.

    Un petit détour par ces traductions pourrait sans doute t'en apprendre d'avantage (dont les articles qui parlent des conditions )
    C'est justement l'un des rares cas dans lequel il peut effectivement être utile et intéressant, avec quelques autres cas vraiment particuliers dans certaines situations particulières.
    Il se trouve que j'ai lu les deux derniers. J'avais trouve ca genial mais je n'ai pas pris le temps de lire les premiers. Erreur qu'il me faut rattraper, merci de me le rappeler.

    Citation Envoyé par koala01 Voir le message
    Mais, dans le cas qui nous intéresse, avec le transtypage qu'il impose, cela devient beaucoup moins lisible à mon sens

    Il n'y a qu'un point d'accès (l'appel de la fonction elle-même) et un point de sortie (le return), donc oui, on a bien respecté SESE
    Je vais t'avouer honnêtement que, à l'heure actuelle, je ne comprend pas non plus l'intérêt de cette règle de codage.

    Cependant, il faut se rappeler que le génie logiciel informatique a maintenant près de 60 ou 70 ans, pendant lesquels il a eu largement l'occasion d'évoluer.

    Il est donc possible de trouver une justification "historique" à cette règle, dans les faits que:
    • certains langages n'autorisaient, à leurs débuts, pas d'avoir plusieurs points de sortie à une fonction
    • les méthodes de représentations d'algorithmes d'origine (flowchart en tête) étaient beaucoup plus lisibles en respectant cette règle

    A vrai dire, je crois que ca doit clairement être évalué au coup par coup, mais je comprends d'autant plus ton point de vue que je considère aussi cette règle comme totalement absurde, actuellement du moins
    oui, parce que tu as très peu de contrôle de type en C et que la taille d'un pointeur est de toutes manière fixe et définitive (pour une architecture donnée), quel que soit le type se trouvant à l'adresse maintenue par le pointeur.
    Bien souvent je trouve les vieux concepts de programmation plutot sympas et tiennent souvent du bon sens (structurer / decouper / limiter arguments de fonctions / limiter taille fonction) alors qu'a l'inverse certains ne servent plus vraiment d'apres ce que j'en vois (SESE en tete ).

    Tiens d'ailleurs je viens de me demander : la POO est-elle un concept de programmation ou bien une definition propre a chaque langage l'implementant (je sais pas si ma question est claire...) ?

    Citation Envoyé par koala01 Voir le message
    C++ tend cependant:
    à éviter au maximum le recours à un void * car on perd "toute information" au sujet de l'objet pointé
    à inciter très largement à l'utilisation du transtypage explicite, afin que l'on puisse plus facilement les retrouver dans le code

    Je peux te rassurer sur ce point:

    Si on apprend les bases du C++ (la syntaxe, les mots clés, peut etre même l'utilisation de la bibliothèque standard) en quelques dizaines d'heures, il faut à tout le monde plusieurs années pour "en faire le tour".

    J'en fais personnellement depuis pas mal de temps, et je rencontre encore souvent des subtilités
    Je m'excuse pour la comparaison mais elle me semble tout a fait adaptee : "Tetris, quelques minutes pour apprendre a y jouer, une vie pour le maitriser".

  10. #10
    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 imperio Voir le message
    Il se trouve que j'ai lu les deux derniers. J'avais trouve ca genial mais je n'ai pas pris le temps de lire les premiers. Erreur qu'il me faut rattraper, merci de me le rappeler.
    Mais de rien, il y a tellement de chose sur le forum qu'on en oublie régulièrement
    Bien souvent je trouve les vieux concepts de programmation plutot sympas et tiennent souvent du bon sens (structurer / decouper / limiter arguments de fonctions / limiter taille fonction) alors qu'a l'inverse certains ne servent plus vraiment d'apres ce que j'en vois (SESE en tete ).
    Je crois, simplement, que c'est dans l'ordre des choses de l'évolution...

    Quelqu'un qui décide de "penser différemment" présente un principe ou un concept et arrive à convaincre ses pairs de l'accepter.

    Ce nouveau principe ou concept occasionne un changement de mentalité peut rendre caduques d'autres concepts ou principes qui avaient toute leur raison d'être auparavant.

    Ce qui importe réellement, c'est de ne pas persister dans une posture que je n'hésiterais pas à traiter de rétrograde

    Penses qu'il y a près de vingt ans, mon père me disait qu'il n'avait pas besoin de l'abs car il était tout à fait en mesure d'obtenir une réaction similaire par sa manière de freiner!!!

    Et, à l'époque, certains bons conducteurs savaient qu'il fallait "pomper" sur le frein lorsque l'on avait tendance à glisser, pour justement limiter la perte d'adhérence.

    A l'heure actuelle, mon père ne voudrait plus d'une voiture sans ABS

    Mais il n'empêche que le fait de se souvenir des "vieux" principes peut s'avérer intéressant, tant qu'on leur donne la position qui leur convient, lorsqu'il s'agit, dans des circonstances bien particulières, de se sortir du pétrin

    SESE est exactement dans la même situation
    Tiens d'ailleurs je viens de me demander : la POO est-elle un concept de programmation ou bien une definition propre a chaque langage l'implementant (je sais pas si ma question est claire...) ?
    Oui ta question est clair, mais non, ce n'est pas une définition propre à chaque langage, ni "tout à fait" un concept de programmation.

    C'est carrément ce que l'on appelle un paradigme, c'est à dire une manière "globale" d'aborder un problème afin d'y apporter une solution.

    L'idée de base du paradigme orienté objets est de penser aux éléments que l'on manipule en terme des services que l'on est en droit d'en attendre, plutôt qu'en terme des données qu'ils manipulent. Les données ne servent "plus qu'à" permettre les éléments manipulés de fournir le service attendu

    Et le principe de base sur lequel on va se baser pour y arriver est la substituabilité (cf : le principe de substitution de Liskov, également connu par son acronyme: LSP )

    Les principes suivi par le paradigme orienté objets sont globalement toujours les mêmes, mais on peut observer que les différents langages ont en définitive chacun leur propre interprétation de ces principes (par exemple : java et C# considèrent qu'il ne peut pas y avoir de fonctions libres, alors que C++ les autorisent )
    Je m'excuse pour la comparaison mais elle me semble tout a fait adaptee : "Tetris, quelques minutes pour apprendre a y jouer, une vie pour le maitriser".
    C'est tout à fait cela...

    A vrai dire, il faut être conscient du fait que C++ est sans doute l'un des langages les plus complexes à cause
    • de son héritage revendiqué de C et de son désir d'assurer la rétro compatibilité
    • du fait qu'il est l'un des rares langages multiparadigmes
    • de sa position qui lui permet bien de travailler tout aussi bien en "bas niveau" (en gérant très finement la mémoire, par exemple) qu'en "haut niveau" (avec son approche OO, par exemple)
    • j'oublie surement l'une ou l'autre raison
    Mais, en définitive, c'est quelque part ce qui fait tout le charme du langage
    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. #11
    Membre émérite
    Avatar de imperio
    Homme Profil pro
    Étudiant
    Inscrit en
    Mai 2010
    Messages
    852
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

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

    Informations forums :
    Inscription : Mai 2010
    Messages : 852
    Points : 2 298
    Points
    2 298
    Par défaut
    Citation Envoyé par koala01
    Oui ta question est clair, mais non, ce n'est pas une définition propre à chaque langage, ni "tout à fait" un concept de programmation.

    C'est carrément ce que l'on appelle un paradigme, c'est à dire une manière "globale" d'aborder un problème afin d'y apporter une solution.

    L'idée de base du paradigme orienté objets est de penser aux éléments que l'on manipule en terme des services que l'on est en droit d'en attendre, plutôt qu'en terme des données qu'ils manipulent. Les données ne servent "plus qu'à" permettre les éléments manipulés de fournir le service attendu

    Et le principe de base sur lequel on va se baser pour y arriver est la substituabilité (cf : le principe de substitution de Liskov, également connu par son acronyme: LSP )

    Les principes suivi par le paradigme orienté objets sont globalement toujours les mêmes, mais on peut observer que les différents langages ont en définitive chacun leur propre interprétation de ces principes (par exemple : java et C# considèrent qu'il ne peut pas y avoir de fonctions libres, alors que C++ les autorisent )
    Voilà qui éclaire ma lanterne. Intéressant en tout cas. D'après ce que j'en ai compris, le principe de substitution de Liskov ça illustre ça en gros :

    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 A
    {
    public:
     A(){}
     int getNb()
     {
        return 3;
     }
    };
     
    class B : public A
    {
    public B() : A(){}
    };
     
    A *test()
    {
      return new B;
    }
     
    int main()
    {
      A  *b = test();
      A->getNb();
      delete A;
      return 0;
    }
    Citation Envoyé par wikipedia
    Si q(x) est une propriété démontrable pour tout objet x de type T, alors q(y) est vraie pour tout objet y de type S tel que S est un sous-type de T.
    Mon exemple illustre leur propos si je ne m'abuse. Ca fait démonstration mathématique.

    Citation Envoyé par koala01
    C'est tout à fait cela...

    A vrai dire, il faut être conscient du fait que C++ est sans doute l'un des langages les plus complexes à cause
    de son héritage revendiqué de C et de son désir d'assurer la rétro compatibilité
    du fait qu'il est l'un des rares langages multiparadigmes
    de sa position qui lui permet bien de travailler tout aussi bien en "bas niveau" (en gérant très finement la mémoire, par exemple) qu'en "haut niveau" (avec son approche OO, par exemple)
    j'oublie surement l'une ou l'autre raison
    Mais, en définitive, c'est quelque part ce qui fait tout le charme du langage
    J'apprécie beaucoup le C++ qui justement permet de faire de "l'objet bas niveau". Mais plus que n'importe quel autre langage, une mauvaise conception ne donnera qu'une catastrophe. C'est le seul défaut que je lui vois vraiment. Quoique, le fait que la lib standard du c++ ne propose pas plus de chose (genre des méthodes de split, join, etc... pour les strings) est légèrement agaçant. 'fin bref, je m'éloigne du sujet là.

  12. #12
    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 imperio Voir le message
    Voilà qui éclaire ma lanterne. Intéressant en tout cas. D'après ce que j'en ai compris, le principe de substitution de Liskov ça illustre ça en gros :

    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 A
    {
    public:
     A(){}
     int getNb()
     {
        return 3;
     }
    };
     
    class B : public A
    {
    public B() : A(){}
    };
     
    A *test()
    {
      return new B;
    }
     
    int main()
    {
      A  *b = test();
      A->getNb();
      delete A;
      return 0;
    }


    Mon exemple illustre leur propos si je ne m'abuse. Ca fait démonstration mathématique.
    Aux erreurs près de ton code, qui devrait etre
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    int main()
    {
      A  *b = test();
      b->getNb();
      delete b;
      return 0;
    }
    c'est en effet LSP qui intervient ici (quoi que cela aille en réalité beaucoup plus loin, une recherche sur le forum sur le terme LSP voir sur "principe de substitution" devrait t'apporter pas mal de réponses intéressantes )
    J'apprécie beaucoup le C++ qui justement permet de faire de "l'objet bas niveau". Mais plus que n'importe quel autre langage, une mauvaise conception ne donnera qu'une catastrophe.
    Toute liberté a son prix
    C'est le seul défaut que je lui vois vraiment. Quoique, le fait que la lib standard du c++ ne propose pas plus de chose (genre des méthodes de split, join, etc... pour les strings) est légèrement agaçant.
    Hummm...

    Le principe de C++ est qu'on ne paye que pour ce qu'on utilise, et donc d'essayer de limiter au grand maximum les dépendances entre les différentes classes.

    C'est, par exemple, la raison pour laquelle les *fstream prennent le nom du fichier sous la forme d'un const char *, afin de ne pas rajouter de dépendance vis à vis de std::string

    Le problème de la fonction split, c'est qu'elle devrait fournir plusieurs chaines au départ d'une seule et qu'il est hors de question de risquer d'en perdre une au passage.

    Il faudrait donc placer les sous chaines dans une collection, mais laquelle un vecteur une liste un set une pile ou une file

    Quelle que soit la solution envisagée, il y aurait toujours quelqu'un pour estimer que ce n'est pas la bonne

    Par contre, la STL fournit "tout ce qu'il faut" (entre autres dans le fichier algoritm / utility ) pour séparer les sous chaines en quelques lignes, te laissant seul juge de la collection dans laquelle tu veux les mettre
    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

  13. #13
    Membre émérite
    Avatar de imperio
    Homme Profil pro
    Étudiant
    Inscrit en
    Mai 2010
    Messages
    852
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

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

    Informations forums :
    Inscription : Mai 2010
    Messages : 852
    Points : 2 298
    Points
    2 298
    Par défaut
    Citation Envoyé par koala01 Voir le message
    Aux erreurs près de ton code, qui devrait etre
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    int main()
    {
      A  *b = test();
      b->getNb();
      delete b;
      return 0;
    }
    c'est en effet LSP qui intervient ici (quoi que cela aille en réalité beaucoup plus loin, une recherche sur le forum sur le terme LSP voir sur "principe de substitution" devrait t'apporter pas mal de réponses intéressantes )
    Oups, my bad !

    Citation Envoyé par koala01 Voir le message
    Toute liberté a son prix
    Hummm...

    Le principe de C++ est qu'on ne paye que pour ce qu'on utilise, et donc d'essayer de limiter au grand maximum les dépendances entre les différentes classes.

    C'est, par exemple, la raison pour laquelle les *fstream prennent le nom du fichier sous la forme d'un const char *, afin de ne pas rajouter de dépendance vis à vis de std::string

    Le problème de la fonction split, c'est qu'elle devrait fournir plusieurs chaines au départ d'une seule et qu'il est hors de question de risquer d'en perdre une au passage.

    Il faudrait donc placer les sous chaines dans une collection, mais laquelle un vecteur une liste un set une pile ou une file

    Quelle que soit la solution envisagée, il y aurait toujours quelqu'un pour estimer que ce n'est pas la bonne

    Par contre, la STL fournit "tout ce qu'il faut" (entre autres dans le fichier algoritm / utility ) pour séparer les sous chaines en quelques lignes, te laissant seul juge de la collection dans laquelle tu veux les mettre
    Il pourrait fournir quelque chose, meme si ce n'est pas la meilleure solution possible dans tous les cas afin de donner "une ligne" a suivre. Rien n'empeche l'utilisateur apres de reimplementer son propre algo. Je trouverai ca plus interessant. Dans la majorite des cas, nous n'avons pas besoin de performance mais juste d'une classe qu'on appelera de temps a autres et qui nous fera ce qu'on lui demande (ce qui est le but de toute classe ).

    Comme je disais, je trouve agacant de toujours reecrire les memes fichiers utilitaires. J'ai fini par m'en faire un que j'utilise partout mais ca fait toujours un fichier en plus.

  14. #14
    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 imperio Voir le message
    Oups, my bad !



    Il pourrait fournir quelque chose, meme si ce n'est pas la meilleure solution possible dans tous les cas afin de donner "une ligne" a suivre. Rien n'empeche l'utilisateur apres de reimplementer son propre algo. Je trouverai ca plus interessant.
    Le fait est que cela créerait une dépendance entre la classe std::string et la collection choisie (quelle qu'elle soit), et c'est cette dépendance qu'il s'agit justement d'éviter.

    Si tu regardes Qt et sa classe QString, tu y trouve une fonction split qui renvoie... une QStringList.

    Bien sur, c'est une fonctionnalité intéressante, mais cela implique que la classe QString dépend de QStringList alors que les cas dans lesquels tu dois utiliser la fonction sont, sommes toutes, assez limités.

    Il est donc dommage de forcer cette dépendance alors que, dans la plupart des cas, tu n'auras absolument pas besoin de la fonctionnalité

    Quand on pense que beaucoup de développeurs (dont je fais partie) estiment déjà que la classe std::string en fait trop, il est inopportun d'aller lui rajouter encore une fonctionnalité qui lui rajoutera, en plus, une dépendance importante, non
    Dans la majorite des cas, nous n'avons pas besoin de performance mais juste d'une classe qu'on appelera de temps a autres et qui nous fera ce qu'on lui demande (ce qui est le but de toute classe ).

    Comme je disais, je trouve agacant de toujours reecrire les memes fichiers utilitaires. J'ai fini par m'en faire un que j'utilise partout mais ca fait toujours un fichier en plus.
    Le standard pourrait, effectivement, rajouter une classe std::string_splitter, par exemple, qui ferait le boulot.

    Mais cela aurait strictement le même résultat: il faudrait rajouter ce fichier pour en profiter, car il est hors de question de le placer dans le fichier <string> ou dans n'importe quel autre

    Ceci dit, quasiment tous les développeurs C++ ont leur série de petits fichiers d'utilitaires "tout faits" qu'il trimbalent de projet en projet
    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

  15. #15
    Membre émérite
    Avatar de imperio
    Homme Profil pro
    Étudiant
    Inscrit en
    Mai 2010
    Messages
    852
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

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

    Informations forums :
    Inscription : Mai 2010
    Messages : 852
    Points : 2 298
    Points
    2 298
    Par défaut
    Citation Envoyé par koala01
    Le fait est que cela créerait une dépendance entre la classe std::string et la collection choisie (quelle qu'elle soit), et c'est cette dépendance qu'il s'agit justement d'éviter.

    Si tu regardes Qt et sa classe QString, tu y trouve une fonction split qui renvoie... une QStringList.

    Bien sur, c'est une fonctionnalité intéressante, mais cela implique que la classe QString dépend de QStringList alors que les cas dans lesquels tu dois utiliser la fonction sont, sommes toutes, assez limités.

    Il est donc dommage de forcer cette dépendance alors que, dans la plupart des cas, tu n'auras absolument pas besoin de la fonctionnalité

    Quand on pense que beaucoup de développeurs (dont je fais partie) estiment déjà que la classe std::string en fait trop, il est inopportun d'aller lui rajouter encore une fonctionnalité qui lui rajoutera, en plus, une dépendance importante, non
    Quand on se sert de la STL, il me parait logique que les classes faisant des split sur des strings en dépendent (l'inverse me paraît difficilement concevable par ailleurs !). Hum... Je crois que c'est mal dit. Plutôt que de fournir une librairie "partielle", autant en fournir une complète et après l'utilisateur choisira ce qu'il veut utiliser. Dans tous les cas, si il en a besoin ça existera, lui évitant de devoir tout se retaper à la main.

    Citation Envoyé par koala01
    Le standard pourrait, effectivement, rajouter une classe std::string_splitter, par exemple, qui ferait le boulot.

    Mais cela aurait strictement le même résultat: il faudrait rajouter ce fichier pour en profiter, car il est hors de question de le placer dans le fichier <string> ou dans n'importe quel autre

    Ceci dit, quasiment tous les développeurs C++ ont leur série de petits fichiers d'utilitaires "tout faits" qu'il trimbalent de projet en projet
    Un fichier à rajouter, c'est pas vraiment la même chose qu'un include (sauf si on s'est compilé notre fichier utilitaire en lib, là ça revient quasiment au même).

  16. #16
    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 imperio Voir le message
    Un fichier à rajouter, c'est pas vraiment la même chose qu'un include (sauf si on s'est compilé notre fichier utilitaire en lib, là ça revient quasiment au même).
    Dans le cas présent, ce n'est effectivement qu'un fichier d'en-tête à rajouter dans le dossier include de ton projet, et à inclure en cas de besoin.

    Dans le pire des cas, c'est dix lignes à réécrire (en comptant les gardes anti inclusion et le cartouche ), que tu pourrais parfaitement finir par connaitre par coeur à force de les réécrire, et qui pourrait parfaitement être "header only"

    Cela peut parfaitement se limiter à cela, même si tu peux envisager d'avoir une bibliothèques "complète" d'utilitaires perso que tu déciderais d'utiliser et avec laquelle tu linkerais tes projets

    Mais, pour un usage professionnel de cette bibliothèque, surtout si tu travailles pour plusieurs clients qui ont des chaines de compilation différentes, tu devrais sans doute de toutes manières recompiler ta bibliothèque pour la chaine de compilation utilisée
    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

  17. #17
    Membre émérite
    Avatar de imperio
    Homme Profil pro
    Étudiant
    Inscrit en
    Mai 2010
    Messages
    852
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

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

    Informations forums :
    Inscription : Mai 2010
    Messages : 852
    Points : 2 298
    Points
    2 298
    Par défaut
    Citation Envoyé par koala01
    Dans le pire des cas, c'est dix lignes à réécrire (en comptant les gardes anti inclusion et le cartouche ), que tu pourrais parfaitement finir par connaitre par coeur à force de les réécrire, et qui pourrait parfaitement être "header only"
    Je les connais déjà par coeur mais ça fait plutôt dans les 200 lignes. C'est un namespace composé de fonctions templatées (donc header only ). Un peu lent à compiler je trouve mais franchement pratique. Je l'ai mis comme source sur developpez.com justement pour plus avoir à le chercher partout dans mon pc.

    Citation Envoyé par koala01
    Mais, pour un usage professionnel de cette bibliothèque, surtout si tu travailles pour plusieurs clients qui ont des chaines de compilation différentes, tu devrais sans doute de toutes manières recompiler ta bibliothèque pour la chaine de compilation utilisée
    Chaîne de compilation ? Après un petit passage sur wikipédia je connais maintenant. Du moment qu'on utilise les compilateurs "standards" du c++ (par là j'entends des compilateurs qui ont pour architecture cible des systèmes d'exploitation non critiques ou modifiés à des fins précises), si le code s'appuie sur la STL il ne devrait pas y avoir besoin de le modifier. Ou alors je me trompe ?

  18. #18
    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 imperio Voir le message
    Je les connais déjà par coeur mais ça fait plutôt dans les 200 lignes. C'est un namespace composé de fonctions templatées (donc header only ). Un peu lent à compiler je trouve mais franchement pratique. Je l'ai mis comme source sur developpez.com justement pour plus avoir à le chercher partout dans mon pc.
    En C++, il ne faut jamais 200 lignes pour créer un splitter de chaines...

    On peut même s'arranger pour qu'il s'adapte à un certain nombre de collections (par exemple, toutes celles qui disposent de la fonction membre push_back) en le rendant template

    La version longue (qui pourrait parfaitement être réduite encore de manière drastique ) ressemblerait à
    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
    #ifndef STRIGSPLITTER_H
    #define STRIGSPLITTER_H
    #include <string> 
    template <typename Collection>
    struct StringSplitter{
        Collection coll;
        Collection operator()(std::string str, char delimiter){ // passage par copie, pour éviter 
                                                                // de modifier la chaine originale
        while(str.find(delimiter)!=std::string::npos){
            std::string temp = str.substr(0,str.find(delimiter);
            coll.push_back(temp);
            str = str.substr(str.find(delimiter)+1);
        }
        /* n'oublions pas la dernière sous chaine */
        coll.push_back(str);
        return coll;
    };
    #endif // STRIGSPLITTER_H
    qui pourrait etre utilisée sous la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    int main(){
    std::string myString;
    /* création ou récupération de la valeur pour myString à ta bonne convenance */
        std::vector<std::string> stringTab = StringSplitter<std::vector<std::string> >()(myString, '/');
        /* utilisation à ta convenance */
    }
    Bon, allez, j'admets que j'avais visé un peu court en comptant une dizaine de lignes, mais on est à dix fois moins que 200 tout de meme
    Chaîne de compilation ? Après un petit passage sur wikipédia je connais maintenant. Du moment qu'on utilise les compilateurs "standards" du c++ (par là j'entends des compilateurs qui ont pour architecture cible des systèmes d'exploitation non critiques ou modifiés à des fins précises), si le code s'appuie sur la STL il ne devrait pas y avoir besoin de le modifier. Ou alors je me trompe ?
    J'ai parlé de recompiler ta bibliothèque, pas de la modifier

    Toutes proportions gardées, pour autant que deux chaines différentes supportent les mêmes fonctionnalités proposées par le langage (car VS2012 ne supporte pas encore toute la norme C++11 ), tu ne devrais pas avoir à modifier le code de ta bibliothèque.

    Par contre, il te sera impossible d'utiliser la bibliothèque générée pour visual studio avec Gcc ou avec clang, et ce, même si tu en fais un bibliothèque dynamique.

    Et l'on ne peut même pas avoir la certitude que la bibliothèque compilée avec VS2008 fonctionnera avec VS2010

    Tu devras donc veiller à compiler ta bibliothèque pour chaque chaine de compilation que tu utiliseras
    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

  19. #19
    Membre émérite
    Avatar de imperio
    Homme Profil pro
    Étudiant
    Inscrit en
    Mai 2010
    Messages
    852
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

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

    Informations forums :
    Inscription : Mai 2010
    Messages : 852
    Points : 2 298
    Points
    2 298
    Par défaut
    Citation Envoyé par koala01
    En C++, il ne faut jamais 200 lignes pour créer un splitter de chaines...

    On peut même s'arranger pour qu'il s'adapte à un certain nombre de collections (par exemple, toutes celles qui disposent de la fonction membre push_back) en le rendant template
    J'ai oublie de preciser que dans les 200 lignes il n'y avait pas que la fonction split (templatee bien entendu) mais bien d'autres. Quoique avec quelques surcharges on atteint assez rapidement les 40 lignes.

    Citation Envoyé par koala01
    Par contre, il te sera impossible d'utiliser la bibliothèque générée pour visual studio avec Gcc ou avec clang, et ce, même si tu en fais un bibliothèque dynamique.

    Et l'on ne peut même pas avoir la certitude que la bibliothèque compilée avec VS2008 fonctionnera avec VS2010

    Tu devras donc veiller à compiler ta bibliothèque pour chaque chaine de compilation que tu utiliseras
    Comme je n'utilise presque que des environnements unix pour mes projets persos, ce probleme n'existe pas vraiment. Par contre je ne savais que d'un VS a l'autre, les libs dynamiques n'etaient pas compatibles ! Ils changent de format de fichier entre chaque version ou quoi ?

  20. #20
    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 imperio Voir le message
    Comme je n'utilise presque que des environnements unix pour mes projets persos, ce probleme n'existe pas vraiment. Par contre je ne savais que d'un VS a l'autre, les libs dynamiques n'etaient pas compatibles ! Ils changent de format de fichier entre chaque version ou quoi ?
    Même sous linux, tu as le problème avec les bibliothèques statiques et dynamiques écrites en C++...

    Pour l'instant, la seule ABI pour laquelle il existe une spécification standard, c'est l'ABI C.

    Il est donc "tout à fait possbile" (attention, je ne dis pas que c'est systématique, hein ) que l'ABI C++ change d'une version de VS ou de Gcc (ou de clang ou de n'importe quel compilateur C++ ) à une autre.

    Cela ne se fera peut etre pas forcément sur les versions "bug fixes" (tu ne devrais pas forcément avoir de problème en utilisant une bibliothèque compilée avec gcc-3.4.1 avec gcc-3.4.1, quoi que je ne puisse pas te l'assurer ), ca risque beaucoup plus d'arriver entre deux version mineures consécutives (une bibliothèque C++ compilée avec Gcc-4.5.x peut ne pas être utilisable avec Gcc-4.6.y) et le risque est vraiment très grand entre deux versions majeures consécutives (tes bibliothèques C++ compilées avec Gcc-3.x.y ont peu de chance d'être utilisable avec Gcc-4.x.y).

    La principale raison est que l'on "peut vraiment espérer" qu'un bugfix ne changera pas l'ABI (et encore, si le bugfix y touche justement... ), que d'une version mineure à une autre, on ne devrait souvent avoir que des corrections relatives aux performances ou à des ajouts de fonctionnalités, mais qu'au niveau des versions majeures, il peut parfaitement arriver qu'une bonne partie de l'ensemble ait, purement et simplement, été refactorée

    Encore un fois, je tiens à préciser que tu n'auras pas forcément le problème de manière systématique entre deux versions majeures, ni que tu l'éviteras systématiquement entre deux bug fixes: je dis juste que tu ne peux avoir strictement aucune certitude à ce niveau, et qu'il faut en tenir compte
    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 1 sur 2 12 DernièreDernière

Discussions similaires

  1. [QReport] Erreur bizarre
    Par vali dans le forum Composants VCL
    Réponses: 3
    Dernier message: 01/03/2009, 01h25
  2. Erreur Bizarre 'copier-coller'
    Par papy_tergnier dans le forum C++Builder
    Réponses: 2
    Dernier message: 21/11/2005, 14h35
  3. Erreur bizarre
    Par ydjilali dans le forum Shell et commandes GNU
    Réponses: 4
    Dernier message: 06/10/2005, 14h52
  4. Le kernel erreur bizarre au chargement d'ext3
    Par Invité dans le forum Administration système
    Réponses: 6
    Dernier message: 01/09/2004, 16h54
  5. [appel de fonction]Erreur bizarre
    Par DEC dans le forum ASP
    Réponses: 4
    Dernier message: 10/08/2004, 17h08

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