7
votes

Pourquoi le compilateur ne prend-il pas le nom de l'espace de noms lorsque la portée intérieure ne fonctionne pas?

Je pensais très bien comprendre la recherche de nom (après avoir regardé plusieurs vidéos à ce sujet et que je lisais beaucoup) mais je viens de toucher ce cas: xxx

la ligne pointue ne compile pas ( sur gcc4.8 et vc11u2) parce qu'il tente d'utiliser la fonction membre Test :: Test :: do_something () au lieu du test d'espace nominal-scoped Test :: do_something (consonstre id et) qui semble être le seul candidat possible.

Apparemment, le nom de la fonction membre masque les noms de l'espace de noms qui me surprenant parce que je me souviens d'utiliser un code presque similaire dans un autre contexte sans ce problème de reproduction (mais le Les conditions peuvent être très différentes à la fin).

Ma question est la suivante: Ces compilateurs confirment-ils à la norme?

(nom de nom est très difficile Pour comprendre en lisant le document standard malheureusement, j'ai besoin de confirmations d'experts)


3 commentaires

Non non. Le nom de nom est facile. Il est juste une petite formule simple.


do_something n'est pas global; C'est dans l'espace de noms .


@cheppner Truem Laisse-moi résoudre ce problème.


5 Réponses :


1
votes

Le compilateur rassemblera tous les "noms candidats", qui seront de la même manière que si l'ADL est impliqué, puis essayez de choisir le meilleur match si on est disponible. En aucun cas, une correspondance échouée ne pourrait en aucun cas pour tenter de trouver des noms de candidats supplémentaires provenant d'alternes étendues.

Ceci est très similaire à la manière dont les compilateurs surchargent la résolution d'abord, puis vérifiez le public / privé du membre pour voir si elle est réellement accessible.

g ++ a une option pratique -wshadow pour chasser les ombres (je ne suis pas sûr qu'elle avertirait celle-ci spécifiquement).


9 commentaires

[BASIC.LOOKUP.UNQUAL] "Le nom de la recherche se termine dès qu'une déclaration est trouvée pour le nom." Est-ce que cela rassemble vraiment tous les noms ?


@Klaim "Soit X l'ensemble de la recherche produite par une recherche non qualifiée (3.4.1) et que vous soyez l'ensemble de recherche produite par la recherche dépendante de l'argument (défini comme suit). Si X contient - une déclaration d'un membre de classe, ou [. ..] Alors y est vide. " basic.lookup.argdep] / 3


@Dyp o____o quoi? J'ai raté cette partie. Donc, si je comprends bien correctement, ADL est effacé ou "supprimé" parce que l'appel est dans un membre de la classe? Cela ne semble pas utile du tout. Quel problème corrige-t-il?


@Klaim: le problème des fonctions d'espace de noms qui constituent un meilleur match voler votre appel de membre?


@Xeo Bon point, mais pourquoi ne pas résoudre ce problème avec un explicite -> - qui serait plus simple imo que de trouver l'espace de noms où la fonction de l'espace de noms est définie et utilisez un identifiant qualifié?


@Xeo DYP a raison, car les règles actuelles interdisent des fonctions génériques non membres à écrire en code générique qui est membre d'une classe, tout en spécifiant l'utilisation du membre au lieu de l'utilisation de la fonction Wastter, est une solution locale à un problème local. Également dans mon cas en cours, aucun nom de membre valide pour l'appel pourrait donc avoir envisagé d'autres noms dans ce cas spécifique.


"Mais pourquoi ne pas résoudre ce problème avec une version explicite->" alors vous devez écrire chaque fonction de membre avec ceci -> , même s'il n'y a pas de fonction externe actuelle qui vole la recherche. Sinon, les modifications futures du code externe pourraient changer la signification de votre code. @DYP


@ Bames53 Je vais bien avec l'écriture ceci -> partout, mais je vois votre point. Surtout si vous autorisez partir ceci -> Il n'y a pas de point de le nécessitant dans la plupart des cas en raison de la recherche de nom.


Je suis pas OK avec l'écriture ceci -> partout. Les règles pas "interdisent des fonctions génériques non membres à écrire dans un code générique qui est membre d'une classe" si vous voulez inclure des noms non membres, puis mettez à l'aide de tester :: do_something; sinon il devrait trouver le nom "le plus proche" (c.-à-d. Partir à partir de la portée actuelle et fonctionner vers l'extérieur dans des étendues jointes)



1
votes

La recherche de nom est très difficile à comprendre en lisant le document standard malheureusement, j'ai donc besoin de confirmations d'experts

Je ne suis pas un expert en aucun cas, mais voici comment je comprends les règles de recherche de noms de la norme.

deux exemples: xxx

(A) ne compile pas, à cause de [BASIC.LOOKUP.UNQUAL]: "La recherche de nom se termine dès qu'une déclaration est trouvée pour le nom"

(b) compile, à cause de l'ADL; associé est un espace de noms associé.

Cependant, il y a [basic.lookup.argdep] / 3:

Soit X le jeu de recherche produit par une recherche non qualifiée (3.4.1) et que vous soyez l'ensemble de recherche produite par l'argument dépendant de la recherche (définie comme suit). Si x contient

  • une déclaration d'un membre de classe, ou
  • une déclaration de fonction de blocage qui n'est pas une déclaration d'utilisation, ou
  • une déclaration qui n'est ni une fonction ni un modèle de fonction

    Alors y est vide. Sinon, y est l'ensemble des déclarations trouvées dans les espaces de noms associés aux types d'arguments comme décrit ci-dessous. L'ensemble des déclarations trouvées à la recherche du nom est l'union de x et y.

    Le premier point s'applique dans votre exemple. Par conséquent, je pense que oui, les compilateurs qui rejetent votre exemple sont conformes à la norme.


2 commentaires

C'est pourquoi on trouvera souvent "Utiliser STD :: Swap;" Dans les mises en œuvre des fonctions d'échange de membres de classe (en plus d'apporter un échange d'échange dans la portée des types fondamentaux tels que int ofc). Empêche la recherche de la fonction d'échange de membre qui empêcherait l'ADL de travailler.


@ Johannesschab-LitB est là un moyen de faire une déclaration visible d'une fonction déclarée dans un espace de noms où l'espace de noms dépend d'un argument de type de modèle?



4
votes

L'autre langue est hors de sa façon de trouver une interprétation valide pour une construction, plus il est probable qu'une faute typographique ou une autre erreur entraînera le compilateur à trouver un sens valide mais mauvais < / em>. Le compilateur suppose que si FOO est défini dans une certaine portée, et que le code de cette portée utilise FOO , le programmateur a l'intention du code d'utiliser le foo qui est défini dans la portée. Si le programmeur tente de faire quelque chose avec foo qui n'est pas autorisé par sa définition de portée intérieure, les chances sont très bonnes que l'une des opérations suivantes est vraie:

  • Le programmeur voulait faire une autre opération légèrement différente, qui aurait été valable sur le FOO interne. Un compilateur n'a pas pu savoir ce que le programmeur entend à moins que le programmeur ne le spécifie.
  • Le programmeur signifiait faire l'opération indiquée, ne réalisant pas que l'intérieur FOO ne peut pas le supporter et devra ainsi trouver une autre opération ou une autre séquence d'opérations l'interne foo peut supporter. Encore une fois, un compilateur ne peut pas être censé générer un bon code à moins que le programmeur indique comment utiliser foo correctement.
  • Le programmeur voulait faire l'opération en question sur le FOO externe, mais a refusé de le dire explicitement. Si le compilateur voulait deviner que c'est ce que le programmeur signifiait, il pourrait générer du code qui se comporterait de cette façon.

    Seulement si l'intention du programmeur était n ° 3, un compilateur peut-il générer du code qui se comporterait comme prévu. C'est beaucoup plus probable qu'un programmeur avait vraiment l'intention de n ° 1 ou n ° 2. Si le compilateur refuse de compiler le code même lorsque cela suppose que le code n ° 3 produirait valide , puis l'une des erreurs ci-dessus sera trouvée et peut ainsi être corrigée. En revanche, si le compilateur supposait n ° 3 chaque fois qu'il pouvait, alors si le programmeur avait vraiment l'intention de problèmes de n ° 1 ou n ° 2 ne se manifesterait pas avant que le code soit exécuté et se comportait contrairement à la conception.

    BTW, si je a eu mes druthers, j'appliquerais ce principe en cas de sensibilité dans les langues .net, interdisant non seulement l'écriture de tout identifiant d'une manière incompatible avec la définition (comme cela est fait par C # mais pas vb.net), mais l'utilisation de tout identifiant qui diffère uniquement dans les boîtiers supérieurs / inférieurs d'une dans une portée intérieure. Par exemple: xxx

    étant donné le code ci-dessus, c # devinerait que la ligne avec les astérisques était destinée à écrire le champ; Compte tenu de code similaire, vb.net supposerait qu'il était destiné à écrire la variable locale. Personnellement, je n'aime pas les deux hypothèses; Le principe de "dise exactement ce que tu veux dire" me suggère qu'un compilateur doit exiger que le programmeur soit indiqué soit this.x = 4; ou x = 4; , aucun dont on ne pourrait éventuellement être lu comme ayant le mauvais sens.


8 commentaires

+1, bien que je ne suis pas d'accord avec utiliser ce partout. C'est un bug qui frappe les débutants, pas un virus qui risque de causer du chaos dans des applications du monde réel. En outre, le compilateur émet un avertissement.


@Eds.: Le seul temps "supplémentaire" que j'aurais besoin ce serait dans le scénario où une variable locale existe avec un nom identique, à l'exception du haut / inférieur. Incidemment, je n'aime vraiment pas la convention C # populaire où le champ de support privé pour la propriété foo est appelé foo ; Je ne vois aucun avantage à cela sur _foo ou _foo . À mon avis, le principal soulignement est plus distinctif que celui des minuscules initiales, et il est légal dans aucun contexte pas moins en tant que noms de champ différents des noms de propriété au cas où seulement.


Ad 3) Je pense que ce n'est pas toujours possible, par exemple Si un type d'argument de fonction est un paramètre de modèle.


@supercat: Oh, alors je suppose que je vous ai mal compris et nous sommes tout à fait d'accord: d. Je n'aime pas les champs de soutien en utilisant uniquement des minuscules aussi pour la même raison; Ils sont en conflit avec les paramètres de la méthode partout.


@Eds.: Beaucoup de gens qui veulent que la sensibilité à l'affaire veuille principalement avoir le compilateur Squawk si des identificateurs sont écrits avec le mauvais cas, et de nombreuses personnes qui souhaitent que l'insensibilité de l'affaire souhaitent principalement avoir le compilateur Squawk si les identificateurs ne diffèrent que par le cas. Pourquoi ne pas rendre les deux groupes de personnes heureuses et exiger que les identifiants soient recouverts correctement, mais également différent de plus que des cas. Il est trop tard pour imposer une telle règle rétrospectivement, mais je penserais que cela aurait offert le meilleur des deux mondes.


@supercat: Parce que je ne rencontre honnêtement jamais de problèmes en raison de la sensibilité des cas (je préfère la sensibilité au cas) et l'écriture ce partout n'ajoute que la verbosité redondante.


@Eds.: Le seul scénario supplémentaire où Ce serait requis serait si un nom de portée interne est presque (à l'exception du cas) correspondant à un nom de portée extérieure. Si vous ne voulez pas écrire Ceci , choisissez un nom de portée intérieure différent différent. Si le code n'a pas besoin d'utiliser le nom de la portée extérieure, il convient de simplement ignorer son existence; Si un nom de portée interne arrive à correspondre, il n'y a pas de problème. Mais je pense que le bon code devrait éviter de créer des noms de portée intérieure qui sont trop similaires aux noms de portée extérieure qu'elle utilise également.


D'accord, c'est pourquoi je suis également d'accord sur le programme de dénomination de champ privé que vous avez mentionné.



6
votes

Ma question est la suivante: sont ces compilateurs confirmant à la norme?

Oui. Avant la résolution de la surcharge décide que les fonctions sont Viables Candidats (qui inclut la vérification du nombre de paramètres), le compilateur doit d'abord faire le nom de recherche, pour trouver tous les candidats, viables et non viables. Dans votre exemple de nom de nom, la recherche s'arrête après avoir trouvé le membre do_something () la résolution de surcharge n'a jamais eu la chance de décider si l'espace d'espace de noms est viable.

3.4.1 [BASIC.LOOKUP.UNQUAL] / 1: "Dans tous les cas énumérés à 3.4.1, les échéanciers sont recherchés une déclaration dans l'ordre indiqué dans chacune des catégories respectives; la recherche de nom se termine dès bientôt comme une déclaration se trouve pour le nom. "

3.4.1 [BASIC.LOOKUP.UNQUAL] Le paragraphe 8 répertorie les contextes recherchés pour le nom et a même un exemple qui répond à votre question exactement. La portée du test est recherchée avant l'espace de nom contenant et, comme le dit le paragraphe 1 indique que la recherche de noms "est terminée dès qu'une déclaration est trouvée pour le nom" . .


0 commentaires

2
votes

Ce n'est pas un problème de recherche du tout. Le point clé est que la recherche complète avant résolution de surcharge. Lorsque le compilateur voit do_something il effectue une recherche pour déterminer ce que cela signifie, il trouve qu'il s'agit d'une fonction, qui activent à son tour ADL pour trouver d'autres surcharges potentielles. Ensuite, la recherche complète et la résolution de surcharge commence. Lorsque la résolution de la surcharge échoue.


0 commentaires