¿Usa `using` en C ++ o lo evita?

17

Descontando semánticas sutilmente diferentes debido a ADL, ¿cómo debería usarlo en general usingy por qué? ¿Depende de la situación (por ejemplo, el encabezado que será #included frente al archivo fuente que no)?

Además, ¿debería preferir ::std::o std::?

  1. Nivel de espacio de nombres using namespace:

    using namespace std;
    
    pair<string::const_iterator, string::const_iterator>
    f(const string &s) {
        return make_pair(s.begin(), s.end());
    }
  2. Siendo completamente explícito:

    std::pair<std::string::const_iterator, std::string::const_iterator>
    f(const std::string &s) {
        return std::make_pair(s.begin(), s.end());
    }
  3. Declaraciones de uso de nivel de espacio de nombres:

    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. Declaraciones de uso de funciones 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. Función local 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. ¿Algo más?

Esto supone que es anterior a C ++ 14 y, por lo tanto, no se utiliza la deducción de tipo de retorno auto.

usuario541686
fuente
2
Consulte stackoverflow.com/questions/1265039/using-std-namespace para obtener un punto de partida.
Programador
@AProgrammer: Ah, gracias por el enlace, que responde parte de mi pregunta. :) Todavía te preguntas acerca ::std::vs std::sin embargo.
user541686
44
stdSin embargo, estoy usando sin segundo. Alguien que define un espacio de nombres estándar está pidiendo problemas (y probablemente está buscando aprovechar la ventaja que la mayoría de la gente está usando stdy no ::std).
Programador

Respuestas:

25

Evite usar usingen encabezados, porque eso rompe el propósito de los espacios de nombres.

Está bien usarlo en archivos fuente, pero aún así lo evitaría en algunos casos (por ejemplo using std).

Sin embargo, si tienes espacios de nombres anidados, está bien:

namespace A {
namespace B {
namespace C {
class s;
} // C
} // B
namespace D{
using B::C::s;
} // D
} // A
BЈовић
fuente
66
+1 es sorprendente la cantidad de tutoriales y cursos universitarios que solo te dicen que uses la usingpalabra clave sin una explicación exhaustiva de por qué se utilizan espacios de nombres para empezar.
Jeffrey Sweeney
La gente quiere seguir usando iostreams, cadenas, etc. No quieren tener que escribir std :: cada vez que quieren usar una cosa, o tienen que recordar otra pieza adicional para poner antes de su código, lo que causará errores poco útiles si lo olvidan . :(
Colen
¿Algo como typedef std :: string sstring; ser una alternativa?
Giorgio
1
@Colen: Estas almas pobres pueden usar using std::couty amigos, pero no coutes como si ya fuera un nombre horriblemente largo.
Benjamin Bannier el
1
Si eres un estudiante universitario en tu primer día de "mi primera clase de C ++", es otra cosa que puede causar errores de sintaxis que no entiendes. Es fácil para nosotros descubrirlo porque somos programadores experimentados, pero cuando estás tratando de aprender el idioma, es otra cosa de la que preocuparte y que no necesitas.
Colen
11

Al poner una declaración de uso en un archivo de origen, POR FAVOR, solo ingrese las cosas que necesita. Por ejemplo:

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

El problema aquí es que si lo haces

using namespace std;

introduces TODAS LAS COSAS desde el estándar en el espacio de nombres global. Lo que conduce a mensajes de error muy interesantes cuando accidentalmente usa un nombre en su código que coincide con uno que no conocía en std. Si solo obtiene las cosas que desea, entonces no tendrá ese problema (o, más precisamente, el próximo programador que trabaje en su código no tendrá ese problema).

Michael Kohne
fuente
Alternativamente, puede using namespacesimplemente en un ámbito de función, evitando el problema.
Tamás Szelei
2
@fish: en realidad, 'usar el espacio de nombres' en el alcance de la función no evita el problema, solo limita el espacio donde las cosas pueden salir mal. Y si termina poniendo 'usando el espacio de nombres' en cada función, no es muy diferente de hacerlo globalmente.
Michael Kohne
Si bien C ++ sí permite declarar tipos en el nivel de función, no es una cosa común; Aparte de eso, los posibles conflictos de nombres son fáciles de detectar desde la salida del compilador (pero tiene razón en que esto no los impide).
Tamás Szelei
2

Como indica VJovic, no lo use usingen un archivo de encabezado. usingen un archivo de encabezado afecta a la unidad de compilación actual (el archivo .cpp) en formas que el archivo de origen puede no estar esperando.

using namespacetambién se debe evitar en un archivo fuente. Esto trae cada símbolo al mismo alcance que el archivo fuente. Es más claro para sus lectores lo que está haciendo si usa símbolos específicos del espacio de nombres.

Bill Door
fuente
2
Como una preocupación práctica, a menos que su código anule los nombres de uso común, preferiría ver using namespace JoystickModuleal comienzo de un archivo .cpp que JoystickModule::adjuntarlo a todos los objetos.
Alex P
@AlexP: Así es exactamente como lo hago. Una usingdeclaración para mi propio espacio de nombres en el que estoy trabajando actualmente y todo lo demás permanece en el espacio de nombres.
Benjamin Kloster
Debería elaborar sobre "usar símbolos específicos del espacio de nombres". En lugar de prefijar cada símbolo en cada uso, lo que no ayuda con la legibilidad, prefiero usar la elevación explícita de símbolos. using SomeNameSpace::SomeSymbol. Esto evita mover todos los símbolos del espacio de nombres al ámbito actual.
Bill Door
0

Escribir usingen encabezados es la mejor manera de crear todo tipo de errores desagradables e imposibles de depurar . No no hacer esto.

Escribir using namespace XYZen el archivo fuente es un poco mejor, pero aún puede causarle innumerables dolores de cabeza. La forma segura es especificar explícitamente lo que está utilizando, por ejemplo using Foo::Bar.

Digamos que tienes Bar.cpp con lo siguiente:

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

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

La función funcionó bien, hasta que un día, aparentemente sin ningún cambio de código en las clases relevantes, su comportamiento cambió: de repente, currentIndexsiempre parece estar desactivado por uno . Al explorar los cambios recientes, no descubre cambios, ni siquiera remotamente relacionados con el código.

Eventualmente descubres la causa:
tú (indirectamente) incluyes en Foo.halguna parte. En los archivos para el espacio de nombres de Foo se agregó una nueva función:

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

Que es una coincidencia inequívocamente mejor increment(int)que su función increment(double), por lo que ahora Foo::increment()se llama a la función en su Bar::someFunction()lugar. Whoops

(Y si tuviera que escribir usingen Encabezados que using namespace Foomuy bien podría estar en cualquier lugar de su árbol de inclusión ...)

Entonces ... No escriba ninguno usingen Encabezados, y también tenga cuidado de escribir using namespaceen archivos fuente.

CharonX
fuente