41 votes

La compréhension de confusion typedef grammaire

Considérons le code suivant-extrait de

typedef int type;
int main()
{
   type *type; // why is it allowed?
   type *k ;// which type?
}

J'obtiens un message d'erreur 'k' is not declared in this scope. Le compilateur traite type *k que la multiplication entre type* et k. N'est-ce pas la grammaire très déroutant?

Pourquoi est - type *type autorisé par la Norme C++? Parce que la grammaire a dit? Pourquoi?

23voto

Mike Seymour Points 130519
type *type; // why is it allowed?

C++11 3.3.2/1 dit:

Le point de la déclaration d'un nom est immédiatement après sa complète de demande de déclaration (article 8) et avant son initialiseur (le cas échéant)

Si le nom de la variable type n'est pas introduit jusqu'à ce que après l'utilisation du nom de type type; le nom du type est le seul sens de l' type lors de la déclaration.

type *k ;// which type?

Le nom de variable locale masque le mondial type de nom, ce qui est choisie ici. Ceci est décrit en C++11 3.3.10/1:

Un nom peut être masquée par une déclaration explicite de même nom dans une étude déclarative de la région ou de la classe dérivée.

Le complet le nom du type, ::type, est bien sûr toujours disponible.

15voto

La question est de savoir quand un nom de variable est définie comme un identifiant, et la langue détermine qu'il est à droite après le point dans le code où la variable est déclarée:

typedef int type;
int main() {
   type t;   // type refers to ::type
   int       // type still refers to ::type
   type;     // variable declared, this shadows ::type
   type + 1; // type is a variable of type int.
}

Il y a des règles similaires dans d'autres contextes, et c'est juste une question de décider quand les identificateurs sont déclarées. Il y a d'autres situations similaires, par exemple dans la liste d'initialisation d'une classe:

struct test {
   int x;          // declare member
   test( int x )   // declare parameter (shadows member)
   : x(            // refers to member (parameter is not legal here)
        x )        // refers to parameter
   {};
};

Ou dans le champ d'application de la identificateurs dans la définition des fonctions membres:

struct test {
   typedef int type;
   type f( type );
};
test::type         // qualification required, the scope of the return type is
                   // at namespace level
test::f(
         type t )  // but the scope of arguments is the class, no qualification
                   // required.
{}

Que de la justification de la décision, je ne peux pas vous dire, mais il est cohérent et simple.

3voto

elmo Points 633

C'est déroutant, mais c'est la seule façon d'obtenir l'accès à l' typevariable. Si vous souhaitez utiliser type type que vous pouvez faire:

typedef int type;
int main() {
    type *type;
    ::type *k ;
    return 0;
} 

La plupart de ceux de la grammaire monstruosités viennent de compatibilité descendante avec C.

1voto

thiton Points 21303

La raison d'être de garder les espaces de noms (pas au sens du C++, mais dans la variable/type d'espace de noms) distincte est assez évident: Lorsque vous ne polluent pas la variable d'espace de noms avec les noms de type, moins de code de ruptures sur les typedef.

Supposons qu'il n'y a pas eu de pré-code existant avec une variable nommée "employé". Si les variables et les typedefs vécu dans le même espace, un "typedef struct {} employé;" casser le code existant, nécessitant un changement du nom de la variable (qui était plus un problème dans les pré-IDE jours). Toutefois, si elles ne pas partager un espace de noms, il n'y a pas de problème et les gens ont un moins question à vous soucier lorsque vous choisissez le type de noms dans les grandes bases de code.

0voto

Nawaz Points 148870

Je pense qu'il est permis sans doute parce qu'il fournit la flexibilité pour les programmeurs lors du choix du nom des variables, ils déclarent. En C#, vous pouvez déclarer propriété de même nom que le type:

//C# code
class Manager
{
   public Name Name {get;set;}
};

Quand je code en C#, je trouve cette fonctionnalité très utile. Parce que j'ai plus d'options pour les noms à choisir. Sinon, si j'ai un type appelé' Name, alors je ne voudrais pas être en mesure de créer une propriété du même nom, je serais forcé de choisir un nom différent, disons Name_, _Name, name, NAME etc - qui ne fait pas appel à moi.


Comme pour votre code, car dans le champ d'application (après la déclaration de l' objet type), type est déjà une variable, le type de type ne peut pas être appelé directement. Mais je pense que cela devrait compiler fine et selon la Norme:

typedef int type;
int main()
{
   type *type; // why is it allowed?
   ::type *k ;// which type?
}

Démo : http://ideone.com/chOov

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X