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 :

Quelques précisions sur la norme 14882 2003


Sujet :

C++

  1. #1
    Débutant  
    Inscrit en
    Novembre 2006
    Messages
    1 073
    Détails du profil
    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 073
    Points : 217
    Points
    217
    Par défaut Quelques précisions sur la norme 14882 2003
    Bonjour

    J'essaye de la norme iso 14882 (enfin, certaines parties) et je ne comprends pas ce qui suit. Il s'agit du § 8.3 Meaning of declarators. J'aimerais bien avoir quelques explications, avec des exemples si possibles.

    A list of declarators appears after an optional (clause 7) decl-specifier-seq (7.1).
    >>On parle d'optional decl-specifiers-seq. Il s'agit bien sur de const, volatile...
    decl-specifier-seq représente const, volatile ou const volatile?

    Each declarator contains exactly one declarator-id; it names the identifier that is declared.
    >>Cela signifie que int signifie int et rien d'autre? Je comprends pas trop. Possible d'avoir un exemple?

    je vous remercie.

  2. #2
    Débutant  
    Inscrit en
    Novembre 2006
    Messages
    1 073
    Détails du profil
    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 073
    Points : 217
    Points
    217
    Par défaut
    bon, c'est vrai qu'il y en avait un peu trop dans mon message précédent.
    J'ai supprimé des choses inutiles.

  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
    Alors, c'est 2 passages de la norme (7 et 8) sont impossantes et concernent tout les genres de déclarations (variable, types, fonctions, ect).

    La première chose, c'est que lire la norme pour la lire (surtout ces passages), c'est inutile.

    Je vais te faire des exemples simplifier pour des déclarations de variable. Pour ca je vais prendre la convention lettre majuscule pour un type (typedef ou class, ect), et lettre minuscule pour une variable.

    Dans ce cas une ligne de déclaration est de la forme (je simplifie, je ne prends pas en compte ce que la norme nomme "attribut")
    decl-specifier-seq init-declarator-list

    decl-specifier-seq est une liste de decl-specifier, qui s'applique à tout les declarators de la init-declarator-list, elle contient (dans notre cas) le type des variables qui seront déclarées par chaque declarator

    un declarator est de la forme [ptr-operator] declarator-id, declarator-id est le nom de la variable, et le ptr-operator facultatif est soit * (éventuellement cv-qualifié), soit &, soit &&

    les différents decl-specifier (dans notre cas) sont ceux des classes de stockage (register, static, thread_local, extern, mutable) ou constexpr (C++2011) ou un type-specifier (cv-qualifier, type, auto)

    Passons à quelques exemples (je prend des exemples courrant du C++, ancien ou récent, donc const,*,&), je sépare tout pour bien voir.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    T t; //1
    T * t; //2
    T const t; //3
    T const & t; //4
    T * const t; //5
    T t1, * t2; //6
    T & t1, t2; //7
    1 : declarator-specifier = T, declarator = t, declarator-id = t
    2 : declarator-specifier = T, declarator = * t, declarator-id = t
    3 : declarator-specifier = T const, declarator = t, declarator-id = t
    4 : declarator-specifier = T const, declarator = & t, declarator-id = t
    5 : declarator-specifier = T, declarator = * const t, declarator-id = t
    6 : declarator-specifier = T, declarator = t1 et * t2, declarator-id = t1 et t2
    7 : declarator-specifier = T, declarator = & t1 et t2, declarator-id = t1 et t2

    On retrouve ce que tu peux trouver dans différente FaQ pour la ligne 7 (en général avec un pointeur), t1 est une référenc sur un T mais t2 est un T et pas une réference sur un T. Par contre sur on remplace T & par U avec typedef T & U, alors t1 et t2 seront tout les deux des U, donc des références sur T, car dans ce cas la référence est inclue dans le type U qui est un declarator-specifier et s'applique donc à tout les declarator.

    En espérant t'avoir aidé.

  4. #4
    Débutant  
    Inscrit en
    Novembre 2006
    Messages
    1 073
    Détails du profil
    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 073
    Points : 217
    Points
    217
    Par défaut
    Merci pour la réponse. Je vais étudier + en détail.
    Sinon, je ne lis pas la norme pour la lire, mais pour approfondir mes connaissances. Par exemple, j'ai lu que si on a:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    typedef int& A;
    const A e=3;
    alors ca marche pas, on essaye d'initialiser une référence non const avec une const. Le typedef annule le caractère const.

    Autre chose:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    struct S{
      S(int);
    }
     
    double a=3;
    S w(int(a));
    S x(int());
    S y((int)a);
    S z=int(a);
    Dans quel cas on a une déclaration de fonction et dans quel cas on a une construction d'objet?

  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
    Tu es certain d'avoir bien compris pourquoi ca ne compile pas ? Les typedef n'annulent pas toujours la constance, dans ton cas c'est vraie à cause de la référence.

    Il y a bien des cas où on peut perdre la constance (en jouant avec les passage de paramètres templates et/ou decltype par exemple), il y a un article de Meyers sur le sujet (cf publication sur C++Next). Et c'est plutôt ce genre d'article que tu devrais lire que la norme, t'apprendras plus de chose, plus vite et c'est bien plus clair ! (La norme c'est bien quand tu cherches un truc précis, pas pour apprendre, AMHA)

    Pour ta question c'est le paragraphe 8.2, qui dit "Si tu peux le voir comme une déclaration, alors c'est une déclaration" (au début, après il détaille d'autre ambiguités), pour nous ca concerne la déclaration des paramètres d'une fonction, dans ton cas on peut voir int (a) et int () comme des déclaration de paramètres, et ainsi ce sont des déclarations de fonctions, alors que dans le troisième (int)a ca ne peut pas être une déclaration de paramètre (syntaxe), c'est donc un cast, donc déclaration (et initialisation) d'un objet, le dernier cas la présence du = donne la réponse.

    NB: Dans le cas de quelque chose de la forne T t(); on pourrais voir une déclaration de fonction ou une déclaration d'objet (et on a pas de paramètre pour savoir), la réponse se trouve dans un NB dans la section concernant l'initialisation, c'est la déclaration d'une fonction. (ou dans toute bonne FaQ)

  6. #6
    Débutant  
    Inscrit en
    Novembre 2006
    Messages
    1 073
    Détails du profil
    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 073
    Points : 217
    Points
    217
    Par défaut
    NB: Dans le cas de quelque chose de la forne T t(); on pourrais voir une déclaration de fonction ou une déclaration d'objet (et on a pas de paramètre pour savoir), la réponse se trouve dans un NB dans la section concernant l'initialisation, c'est la déclaration d'une fonction. (ou dans toute bonne FaQ)
    >>A la page 131 de la norme, on a:

    direct-declarator:
    declarator-id
    direct-declarator ( parameter-declaration-clause ) cv-qualifier-seqopt exception-specificationopt
    direct-declarator [ constant-expressionopt ]
    ( declarator )


    On peut dire que le premier cas, c'est le cas le plus général, le deuxième s'applique aux fonctions et le troisième s'applique aux tableaux.

    Je voudrais avoir un exemple d'un 4ième cas, où direct-declarator c'est du type: (declarator) (avec des parenthèse).

    Par exemple,

    S w(int(a));

    ici, decl-specifier-seq c'est S
    ensuite, le declarator c'est w(int(a)) , mais cet exemple rentre il dans le 4ième cas.

  7. #7
    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
    Je peux pas t'aider pour ca, c'est plus écrit sous cette forme dans le draft du C++2011, et vu qu'il est finalisé tu devrais te référer à celui-ci.

    Mais si je me trompe pas, ca veux juste dire que tu peux mettre des parenthèses autour de ton declarator (ie elles sont facultatives), je ne sais pas si il y a des cas où c'est vraiment utile.

    Pour ton exemple, oui et non, il faut décomposer ton declarator :
    - w c'est le declarator-id
    - ( int(a) ) un parameter-declaration-clause
    - int un decl-specifier-seq pour un parametre
    - ( a ) un declarator-id pour le parametre avec un jeu de parenthèse facultatif

    C'est justement de là que vient l'ambiguité, car de manière général (Type)t ou Type(t) ce sont deux syntaxex valident de covnersion explicite de type, la norme nous dit alors que si la "séquence" (au sens bout de code) peut-être lu comme une déclaration alors c'est une déclaration, or on peut la lire comme une déclaration (déclaration d'un paramètre d'une fonction), donc ton exemple est une déclaration de fonction retournant S, prenant en paramètre un int (le nom du paramètre est a) et son nom est w.

    Pour lever l'ambiguité il suffit de changer la notation utilisée pour la conversion de type, passer avec (int)a, là ca ne peut plus être lu comme une déclaration de function, c'est donc la déclaration d'un objet de type S nommé w initialisé avec un int trantypé depuis l'objet a.

  8. #8
    Débutant  
    Inscrit en
    Novembre 2006
    Messages
    1 073
    Détails du profil
    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 073
    Points : 217
    Points
    217
    Par défaut
    r on peut la lire comme une déclaration (déclaration d'un paramètre d'une fonction), donc ton exemple est une déclaration de fonction retournant S, prenant en paramètre un int (le nom du paramètre est a) et son nom est w.
    ok c'est une convention.

    Sinon, un peu plus loin dans la norme, on a:
    An unqualified-id occuring in a declarator-id shall be a simple identifier except for the declaration of some special functions.
    Peux tu me donner un exemple?

    A declarator-id shall not be qualified except for the definition of a member function or static data member outside of its class, the definition or explicit instantiation of a function or variable member...
    Idem. Que signifie ici qualified?

    Merci

  9. #9
    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
    Je ne garantie pas que ca couvre tout les cas, mais tu as deux sortes d'identifier, les "qualifiés" et les "non-qualifiés", les premiers c'est par exemple A::i, on définie/déclare l'entité i à travers le scope A (mal dit mais je pense que tu devrais comprendre), alors que i est un unqualified-id.

    La première citation te dit que l'unqualified-id doit être un identifiant simple, un identifiant c'est une suite de caractère non reservé par le langage (définition exact en 2.11), sauf pour certaines fonctions spéciales (traité en partie en 12), exemple typique, le constructeur, qui est déclaré/définie en utilisant le nom de la classe, ce n'est donc pas un identifiant simple.

    La seconde te dit que le declarator-id doit être non-qualifié, sauf dans certains cas qu'il énumère, en gros quand tu te réfères à une élément d'une classe hors de celle-ci.

    NB : On es dans le contexte des déclarations/définitions, pas des appels ici.

  10. #10
    Débutant  
    Inscrit en
    Novembre 2006
    Messages
    1 073
    Détails du profil
    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 073
    Points : 217
    Points
    217
    Par défaut
    Je ne garantie pas que ca couvre tout les cas, mais tu as deux sortes d'identifier, les "qualifiés" et les "non-qualifiés", les premiers c'est par exemple A::i, on définie/déclare l'entité i à travers le scope A (mal dit mais je pense que tu devrais comprendre), alors que i est un unqualified-id.
    oK. Je comprends.

    On a la clause 7:
    in simple declaration, the optional init-declarator can be omitted only when declaring a class or enumeration, that is, when the decl-specifier-seq contains either a class-specifier, an elaborated-type-specifier with a class-key or an enum-specifier.
    >>Un exemple?

  11. #11
    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
    Ca veut juste dire que tu peux créer des classes ou des énumérations sans les nommer, c'est assez courrant pour les enum :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    struct A
    {
      enum { a,b }; //L'énumération n'a ici pas de nom
    };
    Pour une classe j'ai un peu du mal à voir à quoi ca peut servir, mais tu peux faire pareil.

  12. #12
    Débutant  
    Inscrit en
    Novembre 2006
    Messages
    1 073
    Détails du profil
    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 073
    Points : 217
    Points
    217
    Par défaut
    ok, je voyais souvent des enum non identifié. Il s'agit donc de cela.

    Sinon, dans la séquence peut-on dire que conformément à la clause 8:

    -int est le decl-specifier
    -(int) (le tout premier en partant de la droite) est le (parameter declaration clause)
    -(*ptf(int)) est le contained declarator-id

    donc conformément à la définition d'une fonction,

    In a declaration T D where D has the form
    D1 (parameter-declaration-clause) cv-qualifier exception-specification,
    and the type of the contained declarator-id in the declaration T D1 is "derived -declarator-type-list-T", the type of the declarator-id in D is: derived-declarator-id-type-list function of (parameter-declaration-clause) cv-qualified-seq returning T',

    peut on dire que T est le int (le tout premier), D1 est (*ptf(int))
    et que l'on a une fonction qui prend un int et qui renvoie un int?

    merci

  13. #13
    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
    Ton analyse est bonne, mais pas ta conclusion.

    Pour répondre à "que signifie int (*foo(int))(int) ?" Je prendrais une approche légèrement différente. Je lis *foo(int) comme un bloc, ca donne donc que *foo(int) est une fonction prenant en paramètre un int et retournant un int.

    Donc foo(int) est un pointeur de fonction prenant un paramètre un int et retournant un int, et finallement foo est une fonction prenant en paramètre un int et retournant un pointeur de fonction prenant en paramètre un int et retournant un int.

  14. #14
    Débutant  
    Inscrit en
    Novembre 2006
    Messages
    1 073
    Détails du profil
    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 073
    Points : 217
    Points
    217
    Par défaut
    Ton analyse est bonne, mais pas ta conclusion.
    Pour analyser, vaut il mieux commencer par l'intérieur, puis vers l'extérieur, donc commencer par le int le plus intérieur,
    ou commencer par le (int) le plus à l'extérieur, celui tout à droite?

    Il s'agit bien sur d'une fonction qui prend un int et qui renvoie un pointeur de fonction. Je m'attendais à qqch comme cela:

    Je lis *foo(int) comme un bloc, ca donne donc que *foo(int) est une fonction prenant en paramètre un int et retournant un int.
    >>qu'est ce qui te permet de dire que le type retournant est un int?

  15. #15
    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
    Je ne sais pas ce qui est le mieux.

    La syntaxe que tu proposes est invalide, ca voudrais dire que int (*)(int) est le decl-specifier, or * ne peut pas apparaitre dans un decl-specifier.

    Si j'appele le bloc que j'ai dit D, alors j'ai : int D (int), ie D1 est une fonction prenant en paramètre un int et retournant un int.

    Mais ce genre de syntaxe est inutile, ca rend le code obscure, il est bien plus clair de passer par un typedef intermédiaire.

  16. #16
    Débutant  
    Inscrit en
    Novembre 2006
    Messages
    1 073
    Détails du profil
    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 073
    Points : 217
    Points
    217
    Par défaut
    Je lis *foo(int) comme un bloc, ca donne donc que *foo(int) est une fonction prenant en paramètre un int et retournant un int.
    >>qu'est ce qui te permet de dire que le type retournant est un int?

Discussions similaires

  1. quelques précisions sur VPN et xdsl
    Par maharam dans le forum Dépannage et Assistance
    Réponses: 0
    Dernier message: 23/09/2010, 16h32
  2. quelques précisions sur mysql
    Par karimero dans le forum Débuter
    Réponses: 4
    Dernier message: 27/01/2010, 17h35
  3. Quelques précisions sur le type double
    Par darkwall_37 dans le forum Débuter
    Réponses: 10
    Dernier message: 10/11/2009, 13h51
  4. Quelques précisions sur html:options collection
    Par weed dans le forum Struts 1
    Réponses: 2
    Dernier message: 19/10/2008, 12h02
  5. Quelques "précisions" sur Struts
    Par Atma_ dans le forum Struts 1
    Réponses: 19
    Dernier message: 03/11/2006, 15h20

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