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 :

un bug de g++ ? les enum fortement typées : mais pas tout à fait x).


Sujet :

C++

  1. #1
    Membre expert

    Avatar de germinolegrand
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Octobre 2010
    Messages
    738
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : Développeur de jeux vidéo
    Secteur : Tourisme - Loisirs

    Informations forums :
    Inscription : Octobre 2010
    Messages : 738
    Points : 3 892
    Points
    3 892
    Par défaut un bug de g++ ? les enum fortement typées : mais pas tout à fait x).
    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
    #include <iostream>
     
    enum myshortenum : unsigned short
    {
        val1,
        val2
    };
     
    void f_int_short(int i)
    {
        std::cout << "f*ck it's an int !" << i;
    }
     
    void f_int_short(unsigned short i)
    {
        std::cout << "cool it's an unsigned short !" << i;
    }
     
    int main()
    {
        myshortenum e = myshortenum::val1;
     
        f_int_short(e);
    }
    Voilà un code minimisé de ce qui risque de mener à ma calvitie prématurée à 4h du matin...

    Selon le standard, quelle devrait être la sortie ?

    Selon moi "cool it's an unsigned short !".

    Selon g++4.7.2 il en est tout autrement... testé sous windows avec mingw32 et linux par Rachel sous 4.8 (et aussi sous ideone pour faire bonne mesure, pas trouvé clang online malheureusement ).

  2. #2
    Membre régulier Avatar de Sytten
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2012
    Messages
    72
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2012
    Messages : 72
    Points : 76
    Points
    76
    Par défaut
    Après une discussion sur skype et une petite recherche google, voici ce que j'ai trouvé:

    C'est un bug du compilateur. Selon §7.2/9 et §4.5/4:
    §7.2/9:
    The value of an enumerator or an object of an unscoped enumeration type is converted to an integer by integral promotion (4.5)

    §4.5/4:
    A prvalue of an unscoped enumeration type whose underlying type is fixed (7.2) can be converted to a prvalue of its underlying type. Moreover, if integral promotion can be applied to its underlying type, a prvalue of an unscoped enumeration type whose underlying type is fixed can also be converted to a prvalue of the promoted underlying type.
    Pas de chance, reste à voir si ça sera réglé dans le futur. À suivre donc...

    Sytten
    À toute erreur il y a une solution

  3. #3
    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
    Avant-propos: Ce message a été édité après rédaction pour corrigé une erreur, voir détail à la fin.

    Ces deux passages sont intéressants, mais ils ne disent pas que c'est une erreur de g++. Tout ce qu'ils disent c'est qu'une enum peut-être convertie en entier par promotion. Et que dans le cas où le type "interne" (j'ai pas de traduction pour "underlying type" mieux que type "interne") est fixé alors les conversions possibles (par promotion) sont celles vers le type "interne" mais aussi celles vers les types promus depuis le type "interne".

    A ces passages ils faut rajouter la section 4.7 qui dit qu'une enum peut aussi être convertie par conversion (et non par promotion) vers les types entiers . (NB: Les "conversions" et "promotions" sont orthogonales, si c'est une promotion alors ce n'est pas une conversion).

    Donc lors de l'appel d'une fonction surchargée pour différents types entiers, l'ensemble des surcharges sont candidates et les séquences de conversions sont toutes de la même "longueur", ce qui va permettre de choisir la surcharge c'est donc le rang de la conversion.

    C'est la que la notion de "promotion" et "conversion" entre en jeu : les promotions ont un rang plus grand que les conversions. Donc dans ton cas avec un type "interne" short, les promotions sont vers short et int (car short peut-être promu en int). On aurait eu une surcharge avec long, la séquence aurait été de type conversion et donc serait déjà éliminé du set de surcharge. Pour sélectionner entre les deux dernières (short et int), il faut regarder le rang de ces deux conversions, dans ce cas celle vers int a un rang plus important, c'est donc elle qui est choisie.

    Norme : 4.5 (§1 §4) , 4.7 (§1 §5) , 4.13 (§1) , 13.3.3.2 (§4)

    4.5

    A prvalue of an integer type [...] whose integer conversion rank (4.13) is less than the rank of int can be converted to a prvalue of type int [...].

    A prvalue of an unscoped enumeration type whose underlying type is fixed (7.2) can be converted to a prvalue of its underlying type. Moreover, if integral promotion can be applied to its underlying type, a prvalue of an unscoped enumeration type whose underlying type is fixed can also be converted to a prvalue of the promoted underlying type.


    4.7

    [...] A prvalue of an unscoped enumeration type can be converted to a prvalue of an integer type.

    The conversions allowed as integral promotions are excluded from the set of integral conversions.


    4.13

    — The rank of a signed integer type shall be greater than the rank of any signed integer type with a smaller size.
    — The rank of long long int shall be greater than the rank of long int, which shall be greater than the rank of int, which shall be greater than the rank of short int, which shall be greater than the rank of signed char.


    13.3.3.2

    Standard conversion sequences are ordered by their ranks: an Exact Match is a better conversion than a Promotion, which is a better conversion than a Conversion. Two conversion sequences with the same rank are indistinguishable unless one of the following rules applies:
    [...]
    — conversion of C to B is better than conversion of C to A,
    4.5

    Une prvalue d'un type entier [...] dans le rang est plus petit que le rang d'un int peut être convertie vers une prvalue de type int. [2]

    Une prvalue d'un type enum dont le type interne est fixé peut être converti vers une prvalue de son type interne. De plus, si une promotion peut être appliqué a son type interne, [elle] peut aussi être convertie vers une prvalue du type promu. [1]


    4.7

    [...] Une prvalue d'un type enum peut être convertie vers une prvalue d'un type entier. [4]

    Les conversions autorisés comme promotions sont exclus de l'ensemble des conversions. [5]


    4.13

    - Le rang de long long int doit être plus grand que le rang de long int, qui doit être plus grand que le rang de int, qui doit être plus grand que le rang de short int, qui doit être plus grand que le rang de signed char. [3]


    13.3.3.2

    Les séquences de conversions standard sont ordonnés par leur rang : une correspondace exact est meilleur qu'une promotion, qui est meilleur qu'une conversion. Deux séquences de conversions avec le même rang sont indiscernables à moins qu'une des règles suivantes s'appliquent : [6]
    - conversion de C à B est meilleur que conversion de C à A.
    [7]
    NB: J'ai omis volontairement la traduction de certains adjectifs, dans notre contexte on parle toujours de conversions entre entiers, et les enum sont "unscoped".

    Pour exemple prenons :
    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
     
    #include<iostream>
     
    enum e : short { val };
     
    void foo(short) //1
    { std::cout << 1; }
     
    void foo(int) //2
    { std::cout << 2; }
     
    void foo(long) //3
    { std::cout << 3; }
     
    int main()
    { foo(val); }
    Étudions les éventuelles appels :
    1. e -> short, d'après [1] c'est donc une promotion
    2. e -> int, d'après [3] le rang de short est inférieur au rang de int, donc d'après [2] short -> int est une promotion, et donc d'après [1] e -> int est une promotion.
    3. e -> long, d'après [4] c'est une conversion. Notons aussi que d'après [5] les deux conversions précédentes sont des promotions et n'entre pas dans l'ensemble des conversions.

    En appliquant [6] on a déjà que //1 et //2 passent avant //3, en appliquant [7] avec [3] on a que //2 passe avant //1. Il n'y a aucune règles en [7] qui vient trancher, l'appel est donc ambiguë.

    En conclusion le code doit afficher 2. C'est le cas sous VS2012 et g++ 4.7.1
    C'est donc bien un problème de VS2012 et g++ 4.7.1

    PS: Cependant je dois oublier un détail, en effet en mettant uniquement les surcharges //1 et //3 je m'attendais à ce que ça compile et que //1 soit appelé, mais ce n'est pas le cas, il trouve une ambiguïté. Comme si le type interne était toujours int. Ce constat reste problématique, il devrait appeler //1 et pas trouver une ambiguïté, comme si le type interne était toujours int (comportement en cas d'enum "classique" C++03).

    PPS: Il semblerait que la règle que je cite en [7] n'ai rien à voir avec les integer conversion rank [3]. Ça change donc l'interprétation et la conclusion.

  4. #4
    Membre expert

    Avatar de germinolegrand
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Octobre 2010
    Messages
    738
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : Développeur de jeux vidéo
    Secteur : Tourisme - Loisirs

    Informations forums :
    Inscription : Octobre 2010
    Messages : 738
    Points : 3 892
    Points
    3 892
    Par défaut
    Il me semble avoir lu sur le lien que sytten m'a cité hier que Clang avait résolu cela...
    edit2: les liens en question :
    (en) http://stackoverflow.com/questions/1...ed-enum-in-c11
    (en) http://stackoverflow.com/questions/1...resolve-to-fct
    edit: il a résolu en respectant le standard à la lettre : l'appel doit être ambigu si l'on suit le standard.

    Et ce qui est certain c'est que si ce n'est pas un bug de compilo, alors c'est la norme qui est fautive, l'appel de la surcharge correcte marcherait pour la moitié des types mais pas les autres... ça m'apprendra à vouloir gérer l'endianness en sérialisant des enum...

  5. #5
    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
    Après appronfondissement, il s'avère que j'ai surment mal compris une partie des éléments de la norme relatifs à ce problème. J'ai édité pour corrigé, ça me semble déjà mieux.

  6. #6
    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 germinolegrand Voir le message
    Il me semble avoir lu sur le lien que sytten m'a cité hier que Clang avait résolu cela... edit: il a résolu en respectant le standard à la lettre : l'appel doit être ambigu si l'on suit le standard.
    Pareil sous VS2012
    1>main.cpp(25): error C2668: 'f_int_short' : ambiguous call to overloaded function
    1> main.cpp(14): could be 'void f_int_short(unsigned short)'
    1> main.cpp(9): or 'void f_int_short(int)'
    1> while trying to match the argument list '(myshortenum)'
    Mais si c'est bien l'intention de la norme c'est quand même un choix bizarre, soit c'est typé et ça "devrait" passer soit c'est pas vraiment typé et on se retrouve avec des enums "normales".

Discussions similaires

  1. Réponses: 1
    Dernier message: 07/01/2008, 14h15
  2. Patcher le noyau mais pas toutes les bases
    Par scheu dans le forum Administration
    Réponses: 4
    Dernier message: 16/10/2007, 19h06
  3. Réponses: 5
    Dernier message: 16/12/2006, 22h29
  4. Lag dans les requêtes des répliques mais pas du maître
    Par Thomas JOUANNOT dans le forum Access
    Réponses: 3
    Dernier message: 16/03/2006, 09h17

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