Quelle est la portée de la déclaration «using» en C ++?

100

J'utilise la déclaration «using» en C ++ pour ajouter std :: string et std :: vector à l'espace de noms local (pour éviter de taper des «std ::» inutiles).

using std::string;
using std::vector;

class Foo { /*...*/ };

Quelle est la portée de cette déclaration? Si je fais cela dans un en-tête, injectera-t-il ces déclarations «using» dans chaque fichier cpp qui inclut l'en-tête?

Jeff Lake
la source
18
Juste au cas où cela ne serait pas clair d'après les autres réponses ici: - Ne mettez pas de usingdéclaration (ou usingdirective) à la portée du fichier dans un fichier / en-tête d'inclusion! Cela causera des maux de tête aux utilisateurs de l'en-tête.
Michael Burr
En fait, ne pas mettre une usingdéclaration (a fortiori directive ) dans un en- tête du tout , même dans un espace de noms! Voir la portée de la déclaration d'utilisation dans un espace de noms pour les problèmes que cela provoque.
Nils von Barth
@NilsvonBarth: C'est un peu simplifié. L'utilisation usingdans la portée de la classe et de la fonction est sûre par rapport au problème discuté.
Sebastian Mach
Vous voudrez peut-être en savoir plus sur la fonctionnalité de recherche ADL C ++ .
Alexis Wilke

Réponses:

59

Lorsque vous #incluez un fichier d'en-tête en C ++, il place tout le contenu du fichier d'en-tête à l'endroit où vous l'avez inclus dans le fichier source. Donc, inclure un fichier qui a une usingdéclaration a exactement le même effet de placer la usingdéclaration en haut de chaque fichier qui inclut ce fichier d'en-tête.

Jeremy Ruten
la source
51
... ce qui est généralement une mauvaise chose.
Catskul
17
Mais si vous mettez la usingdéclaration dans un, namespaceelle est limitée à la portée de cet espace de noms, donc c'est généralement OK (avec les mises en garde habituelles sur vos besoins et votre style particuliers).
Zero
1
... mais si vous mettez using dans un espace de noms, assurez-vous de ne pas le faire pour essayer de contourner quelque chose qui est normalement une mauvaise idée, comme vous ne pouvez pas encapsuler les méthodes de classe déclarées en dehors de l'espace de noms Y dans l'autre namespace X, juste pour que vous puissiez utiliser localement l'espace de noms X. C'est pourquoi nous avons utilisé namespace :: resolvers en premier lieu. Si c'est un gros problème de frappe, que ce soit une macro (qui peut facilement conduire à des odeurs de code) ou mieux encore, isolez-la dans sa propre source .cpp où vous utiliserez l'espace de noms uniquement.
osirisgothra
1
Bien que ces réponses et des réponses similaires soient de bons conseils, elles ne répondent pas à la question.
Emile Cormier
116

Il n'y a rien de spécial dans les fichiers d'en-tête qui empêcherait la usingdéclaration. C'est une simple substitution de texte avant même que la compilation ne commence.

Vous pouvez limiter une usingdéclaration à une portée:

void myFunction()
{
   using namespace std; // only applies to the function's scope
   vector<int> myVector;
}
Éclipse
la source
12
Je n'ai jamais pensé que je pourrais l'utiliser dans une fonction!
Agostino
1
J'ai un tas d'espaces de noms tous utilisés par un fichier de type "conglomérateur", et les tests unitaires gmock étaient très fastidieux car chaque test utilisait des éléments d'un espace de noms spécifique, et je pensais que je devais qualifier chaque variable. Utiliser à l' usingintérieur d'une fonction (ou même d'une TESTmacro gtest !) Rend ma vie tellement meilleure!
dwanderson
54

La portée de l'instruction using dépend de son emplacement dans le code:

  • Placé en haut d'un fichier, il a une portée dans tout ce fichier.
  • S'il s'agit d'un fichier d'en-tête, il aura une portée dans tous les fichiers qui incluent cet en-tête. En général, ce n'est " pas une bonne idée " car cela peut avoir des effets secondaires inattendus
  • Sinon, l' instruction using a une portée dans le bloc qui la contient du point où elle se produit jusqu'à la fin du bloc. S'il est placé dans une méthode, il aura une portée dans cette méthode. S'il est placé dans une définition de classe, il aura une portée dans cette classe.
dagoryme
la source
5
Je pensais qu'il n'était pas possible d'ajouter une usinginstruction dans la portée de la classe ...? J'avais la même question que l'OP à cause de cela car je voulais éviter de taper std::partout. J'ai des classes qui utilisent beaucoup de vecteurs avec des pointeurs intelligents et le std::préfixe à cinq caractères ajoute beaucoup de longueur de ligne - ce que je trouve pire. Donc je me demandais si une usingdirective dans l'espace de noms contenant la classe était ok? (Même si dans un en-tête.)
thomthom
5
Qu'en est-il s'il est placé dans le cadre d'un namespace { ... }?
einpoklum
Vous pouvez donc totalement écrire: {using namespace blabla; class blah {}; } et que l'utilisation s'appliquera uniquement à la classe?
Dinaiz
8

La portée est quelle que soit la portée de la déclaration using.

S'il s'agit d'une portée mondiale, alors ce sera une portée mondiale. S'il est dans la portée globale d'un fichier d'en-tête, alors il sera dans la portée globale de chaque fichier source qui comprend l'en-tête.

Ainsi, le conseil général est d' éviter d'utiliser des déclarations dans la portée globale des fichiers d'en-tête .

JohnMcG
la source
3
Ce n'est pas assez fort. Remplacez éviter par Ne pas
Martin York
1
BUt éviter est plus fort que ne le faites pas. «Évitez de heurter les autres voitures»
bobobobo
6

Dans le cas cité, le fichier ("unité de traduction"), ce qui signifie oui, chaque fichier qui le comprend.

Vous pouvez également placer l'instruction using à l'intérieur de la classe, auquel cas, elle n'est effective que pour cette classe.

En règle générale, si vous devez spécifier un espace de noms dans un en-tête, il est souvent préférable de simplement qualifier complètement chaque identifiant nécessaire.

James Curran
la source
Notez que la usingdéclaration dans une classe ne se comporte pas de la même manière qu'en dehors d'une classe - par exemple, vous ne pouvez pas l'utiliser pour amener à la coutplace de std::coutdans la portée de la classe.
Zero
2

C'est correct. La portée est le module qui utilise la usingdéclaration. Si des fichiers d'en-tête inclus dans un module ont des usingdéclarations, la portée de ces déclarations sera ce module, ainsi que tous les autres modules qui incluent les mêmes en-têtes.

Ates Goral
la source
1

Il y a quelques commentaires qui sont plutôt sans réserve quand ils disent "Ne pas". C'est trop sévère, mais il faut comprendre quand ça va.

L'écriture using std::stringn'est jamais OK. Ecrire using ImplementationDetail::Foodans votre propre en-tête, lorsque cet en-tête déclare ImplementationDetail :: Foo peut être OK, plus encore si la déclaration using se produit dans votre espace de noms. Par exemple

namespace MyNS {
    namespace ImplementationDetail {
        int Foo;
    }
    using ImplementationDetail::Foo;
}
MSalters
la source
1
L'utilisateur de l'en-tête peut alors écrireMyNS::Foo
Peter Remmers
Un meilleur exemple est using boost::posix_time::ptime. Bien sûr, l'utilisateur peut écrire, MyNS::ptimemais ce n'est pas la fin du monde, et pourrait être compensé par la commodité de pouvoir avoir des fonctions comme MyFunction(ptime a, ptime b).
Zero
5
Pourquoiusing std::string ça ne va jamais? Même dans votre propre espace de noms pour enregistrer beaucoup de std::préfixes?
thomthom
@thomthom c'est correct lorsqu'il est enveloppé dans une portée telle que votre propre espace de noms.
jcoffland