Utiliser `using` en C ++ ou l'éviter?

17

En actualisant la sémantique subtilement différente en raison de l'ADL, comment dois-je généralement l'utiliser usinget pourquoi? Est-ce dépendant de la situation (par exemple, en-tête qui sera #included contre fichier source qui ne le sera pas)?

De plus, devrais-je préférer ::std::ou std::?

  1. Au niveau de l'espace de noms using namespace:

    using namespace std;
    
    pair<string::const_iterator, string::const_iterator>
    f(const string &s) {
        return make_pair(s.begin(), s.end());
    }
  2. Être pleinement explicite:

    std::pair<std::string::const_iterator, std::string::const_iterator>
    f(const std::string &s) {
        return std::make_pair(s.begin(), s.end());
    }
  3. Déclarations d'utilisation au niveau de l'espace de noms:

    using std::pair;
    using std::string;
    
    pair<string::const_iterator, string::const_iterator>
    f(const string &s) {
        return make_pair(s.begin(), s.end());
    }
  4. Fonction en utilisant les déclarations locales:

    std::pair<std::string::const_iterator, std::string::const_iterator>
    f(const std::string &s) {
        using std::make_pair;
        return make_pair(s.begin(), s.end());
    }
  5. Fonction locale using namespace:

    std::pair<std::string::const_iterator, std::string::const_iterator>
    f(const std::string &s) {
        using namespace std;
        return make_pair(s.begin(), s.end());
    }
  6. Autre chose?

Cela suppose une pré-C ++ 14, et donc pas de déduction de type retour en utilisant auto.

user541686
la source
2
Voir stackoverflow.com/questions/1265039/using-std-namespace pour un point de départ.
Programmeur
@AProgrammer: Ah, merci pour le lien, qui répond à une partie de ma question. :) Toujours à propos de se demander par ::std::rapport à std::bien.
user541686
4
J'utilise stdsans seconde cependant. Quelqu'un définissant un espace de noms std demande des problèmes (et cherche probablement à tirer profit de ce que la plupart des gens utilisent stdet non ::std).
Programmeur

Réponses:

25

Évitez d'utiliser usingdans les en-têtes, car cela rompt le but des espaces de noms.

Il est correct de l'utiliser dans les fichiers source, mais je l'éviterais quand même dans certains cas (par exemple using std).

Cependant, si vous avez des espaces de noms imbriqués, c'est ok:

namespace A {
namespace B {
namespace C {
class s;
} // C
} // B
namespace D{
using B::C::s;
} // D
} // A
BЈовић
la source
6
+1, il est étonnant de voir combien de didacticiels et de cours universitaires vous disent simplement d'utiliser le usingmot - clé sans expliquer en détail pourquoi les espaces de noms sont utilisés au départ.
Jeffrey Sweeney
Les gens veulent continuer à utiliser les iostreams, les chaînes, etc. Ils ne veulent pas avoir à taper std :: chaque fois qu'ils veulent utiliser une chose, ou doivent se rappeler encore un autre morceau de passe-partout à mettre avant leur code, ce qui provoquera des erreurs moins utiles s'ils l'oublient . :(
Colen
Souhaitez quelque chose comme typedef std :: string sstring; être une alternative?
Giorgio
1
@Colen: Ces pauvres âmes peuvent utiliser using std::coutet amis, mais ce n'est pas comme si c'était coutdéjà un nom horriblement long.
Benjamin Bannier
1
Si vous êtes un étudiant dans votre premier jour de "ma première classe C ++", c'est encore une autre chose qui peut provoquer des erreurs de syntaxe que vous ne comprenez pas. C'est facile pour nous de comprendre parce que nous sommes des programmeurs expérimentés, mais lorsque vous essayez d'apprendre la langue, c'est encore une autre chose à vous soucier dont vous n'avez pas besoin.
Colen du
11

Lorsque vous placez une instruction using dans un fichier source, S'IL VOUS PLAÎT, insérez simplement les éléments dont vous avez besoin. Par exemple:

using std::string;
using std::ostringstream;

Le problème ici est que si vous le faites

using namespace std;

vous tirez CHAQUE SINGLE THING de std dans l'espace de noms global. Ce qui conduit à des messages d'erreur très intéressants lorsque vous utilisez accidentellement un nom dans votre code qui correspond à celui que vous ignoriez complètement dans std. Si vous insérez simplement ce que vous voulez, vous n'aurez pas ce problème (ou, plus précisément, le prochain programmeur à travailler sur votre code n'aura pas ce problème).

Michael Kohne
la source
Alternativement, vous pouvez using namespacesimplement dans une étendue de fonction, en évitant le problème.
Tamás Szelei
2
@fish - en fait, faire «utiliser l'espace de noms» dans la portée de la fonction n'évite pas le problème, cela limite simplement l'espace où les choses peuvent mal se passer. Et si vous finissez par mettre «en utilisant l'espace de noms» dans chaque fonction, ce n'est pas très différent de simplement le faire globalement.
Michael Kohne
Bien que C ++ permette en effet de déclarer des types au niveau de la fonction, ce n'est pas chose courante; à part cela, les conflits de noms possibles sont faciles à repérer à partir de la sortie du compilateur (mais vous avez raison, cela ne les empêche pas).
Tamás Szelei
2

Comme l'indique VJovic, ne l'utilisez pas usingdans un fichier d'en-tête. usingdans un fichier d'en-tête affecte l'unité de compilation actuelle (le fichier .cpp) d'une manière que le fichier source peut ne pas attendre.

using namespaceest également à éviter dans un fichier source. Cela met chaque symbole dans la même portée que le fichier source. Vos lecteurs savent plus clairement ce que vous faites si vous utilisez des symboles spécifiques de l'espace de noms.

Bill Door
la source
2
En tant que préoccupation pratique, à moins que votre code ne remplace les noms couramment utilisés, je préfère de loin voir using namespace JoystickModuleau début d'un fichier .cpp que JoystickModule::attaché à chaque objet.
Alex P
@AlexP: C'est exactement comme ça que je le fais. Une usingdéclaration pour mon propre espace de noms sur lequel je travaille actuellement et tout le reste reste à espace de noms.
Benjamin Kloster
Je devrais élaborer sur "utiliser des symboles spécifiques de l'espace de noms". Plutôt que de préfixer chaque symbole à chaque utilisation, ce qui n'aide pas à la lisibilité, je préfère utiliser le levage explicite des symboles. using SomeNameSpace::SomeSymbol. Cela évite de déplacer chaque symbole de l'espace de noms dans la portée actuelle.
Bill Door
0

L'écriture usingdans les en-têtes est le meilleur moyen de créer toutes sortes de bugs désagréables et impossibles à déboguer . Ne fais pas ça.

Écrire using namespace XYZdans le fichier source est un peu mieux, mais peut toujours vous causer d'innombrables maux de tête. Le moyen sûr est de spécifier explicitement ce que vous utilisez, par exemple using Foo::Bar.

Disons que vous avez Bar.cpp avec les éléments suivants:

//Bar.cpp
using namespace Foo;
namespace
{
    double increment(double v) { return (v + 1); }
}

void Bar::someFunction()
{
    //...
    int currentIndex = 0;
    int nextIndex = increment(currentIndex);
    //...
}

La fonction a bien fonctionné, jusqu'à ce qu'un jour - apparemment sans aucun changement de code dans les classes pertinentes - son comportement ait changé: Soudain, currentIndexil semble toujours être désactivé par un . En fouillant dans les changements récents, vous ne découvrez aucun changement, même à distance, lié au code.

Finalement, vous découvrez la cause:
vous (indirectement) incluez Foo.hquelque part. Dans les fichiers de l'espace de noms Foo, une nouvelle fonction a été ajoutée:

//Foo.h
namespace Foo
{
    //...
    int& increment(int& v) { v += 1; return v; };
    //...
}

Ce qui correspond sans aucun doute mieux increment(int)que votre fonction increment(double)- alors maintenant, la Foo::increment()fonction est appelée par Bar::someFunction(). Oups.

(Et si vous deviez écrire des usingen-têtes qui using namespace Foopourraient très bien se trouver n'importe où dans votre arbre d'inclusion ...)

Alors ... N'en écrivez pas usingdans les en-têtes, et méfiez-vous également de l'écriture using namespacedans les fichiers source.

CharonX
la source