11
votes

Comment fonctionne la résolution de surcharge de l'opérateur dans les espaces de noms?

J'ai trouvé un comportement étrange de résolution C ++ de la surcharge de l'opérateur, je ne peux pas m'expliquer moi-même. Un pointeur à une ressource décrivant que ce serait aussi agréable qu'une réponse.

J'ai 2 unités de traduction. Dans un (appelé util.cpp / h), je déclare et définit deux opérateurs (j'espérais les implémentations réelles de lectuabilty, le problème se produit quand même): p> xxx pré>

et: P>

//test.cpp
#include "test.h"
#include "util.h"
#include <iostream>

void Namespace::SomeClass::test(std::istream& is) {
  ::operator>>(is, "c"); //works
  is >> "c" //fails
}


4 commentaires

Avez-vous essayé de déclarer l'espace de noms :: opérateur >> comme «inline»


BTW, il vous manque un ; après votre déclaration de classe


a couché le;. C'est une erreur très habituelle que je fais ...


@ Bert-jan Non, car dans ma mise en œuvre réelle, le flux d'entrée est analysé avec quelques amout de code, que je trouve beaucoup à être inlincé.


3 Réponses :


0
votes

:: est la portée globale, le compilateur doit donc numériser l'espace de noms global et trouver cet opérateur. est >> "C", en essayant de trouver l'opérateur >> dans l'espace de noms, donc, le compilateur trouvez-le et arrêtez la recherche, puis compilateur essayer de choisir l'opérateur avec la signature nécessaire, s'il n'y a pas de tel opérateur - compilateur échoue. Je pense que vous devriez lire Souput Herb Exceptionnel C ++.


0 commentaires

10
votes

Il s'agit d'un nom de cache-cache. La norme dit (C ++ 03, 3.3.7 / 1)

Un nom peut être masqué par une déclaration explicite de ce même nom dans une région déclarative imbriquée ou dérivée classe (10.2).

le "nom" sur votre cas serait opérateur >> et les espaces de noms constituent des régions déclaratives imbriquées.

Le moyen le plus simple de résoudre ce serait à utiliser un en utilisant déclaration où vous déclarez l'opérateur <<<<<< / code>: xxx

Notez que cette fonctionnalité ne veut pas interférer avec la recherche koenig (au moins dans votre cas, en principe, cela peut), de sorte que les opérateurs IO de std :: seront toujours trouvés.

PS: une autre possibilité de travailler Aroud Ce numéro définirait l'opérateur de Someclass comme Inline ami . De telles fonctions sont déclarées au niveau de l'espace de noms (en dehors de "leur" classe), mais ne sont pas visibles de là. Ils ne peuvent être trouvés que par Koenig Recherche.


3 commentaires

Est-ce un concept utile? Je veux dire que je comprends bien, mais ne serait-il pas plus utile de regarder partout, si aucune signature ne va pas? (Cela ne devrait pas offenser la réponse, mais la norme C ++ :))


@hildensia a l'air de vaincre n'importe où dans le but des espaces de noms et vous courez le risque de ramasser des choses que vous n'avez jamais entendues, à cause des affrontements de nom.


@hildensia: Je ne connais pas vraiment la raison d'une telle caractéristique, mais je suppose que cela va de la tradition C de nom de nom de nom (où une variable dans une portée intérieure cache la variable de la portée extérieure), qui est en fait la droite chose à faire imho. Ensuite, vous devez envisager des problèmes tels que "si j'ai un char * a dans une portée intérieure et un int a dans une portée extérieure, le externe) être trouvé où un int conviendrait? " Je pense que le processus de masquage de nom vous donne en réalité un environnement plus prévisible, par exemple. Les matchs de surcharge non parfaits ne seront pas perturbés par une personne déclarée dans la portée extérieure.



3
votes

Il y a plusieurs problèmes ici; Pour commencer, vous redéfinissez un Fonction dans l'espace de noms global qui existe déjà dans std :: . Les Le problème que vous décrivez, cependant, est dû à la façon dont le nom de recherche fonctionne. Fondamentalement, dans le cas de la surcharge de l'opérateur, le compilateur fait deux Nom Recherches. Le premier (utilisé pour tous les symboles, pas seulement les opérateurs) commence à la portée où le symbole apparaît et fonctionne vers l'extérieur: d'abord les blocs locaux, puis la classe et ses classes de base (le cas échéant), et Enfin, les espaces de noms, travaillant à l'espace de noms global. Un caractéristique importante de cette recherche est qu'il s'arrête dans tout ce que Portée Il trouve le nom: s'il trouve un nom dans la portée locale, il ne doit pas regarde dans toutes les classes; S'il en trouve un dans une classe, il ne regarde pas dans le classes de base ou espaces de noms, et s'il en trouve un dans un espace de noms, il Ne regarde pas dans des espaces de noms entourant. En ce qui concerne cette recherche est concerné, toutes les surcharges doivent être dans la même portée. La seconde recherche affecte uniquement les fonctions et les surcharges de l'opérateur et se produit dans le contexte des classes ou des objets utilisés comme arguments; Ainsi, si l'un des opérandes est une classe dans la bibliothèque standard (ou quelque chose dérivé d'une classe dans le Bibliothèque standard), le compilateur recherchera des fonctions dans std :: , même Bien que le contexte où le symbole est utilisé n'inclut pas std :: . Le problème que vous rencontrez est des types intégrés, tels que char * , ne pas implique tout espace de noms (pas même global): Compte tenu de vos surcharges, le premier recherche s'arrêtera au premier opérateur >> il voit et le second seul regarde dans std :: . Votre fonction est en ni l'un ni l'autre. Si vous voulez un opérateur surchargé à trouver, vous devez le définir dans la portée de un de ses opérandes.

concrètement, ici: vous ne pouvez pas surcharger std :: istream & opérateur >> (std :: istream &, char *) , car il est déjà surchargé dans la bibliothèque standard. std :: istream et opérateur >> (std :: istream &, char const *) est possible, mais je ne suis pas sûr de ce que c'est censé faire, car Il ne peut pas écrire au deuxième opérande. Plus généralement, vous ne devriez que surcharger cet opérateur pour des types que vous avez définis et que vous devriez mettre votre surcharge dans la même espace de noms que le type lui-même, de sorte qu'il sera trouvé par la seconde recherche ci-dessus (appelé argument dépendant Recherche ou ADL-ou antérieur, Koenig Recherche, après la personne qui inventé).


3 commentaires

Il est en fait destiné à analyser à partir d'un flux d'entrée. où vous écrivez os << "[" << matrix << "]"; Vous pouvez simplement écrire est >> "[" >> matrice >> "]"; . Il est censé être un peu "Syntaxtic Suggar" dans le code hérité, je dois utiliser. Je voulais nettoyer certaines choses, pour la rendre compilée avec Clang et couru dans ce problème.


Et vous voulez une correspondance exacte, sans stocker les résultats n'importe où? Cela ressemble à un manipulateur, plus qu'un extracteur. Mais vous devriez écrire est >> match ("[") >> Matrix >> Match ("]") ou quelque chose de similaire. Le problème avec la façon dont vous essayez de le faire est que opérateur >> (iStream &, char *) a déjà une signification définie et cette surcharge sur Const ( Char Const * vs. Char * ) ne fera aucune fin de confusion si les surcharges font des choses totalement indépendantes. Donc, autant que j'aime la syntaxe, vous essayez d'atteindre, je ne suis pas sûr que ce soit une bonne idée.


C'est un peu déroutant, vous avez raison, mais ce n'est pas dans mon champ de changement ... mais je vais supprimer la chose non-constance, car elle n'est pas utilisée de toute façon. Il est réellement destiné à juste correspondre à partir du Istream et de jeter la chaîne. Si vous avez un protocole surhead, c'est un peu pratique.