Qual é o escopo da declaração “usando” em C ++?

100

Estou usando a declaração 'usando' em C ++ para adicionar std :: string e std :: vector ao namespace local (para evitar a digitação desnecessária de 'std ::' s).

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

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

Qual é o escopo desta declaração? Se eu fizer isso em um cabeçalho, ele injetará essas declarações de 'uso' em cada arquivo cpp que inclua o cabeçalho?

Jeff Lake
fonte
18
Caso não esteja claro com as outras respostas aqui: - Não coloque uma usingdeclaração (ou usingdiretiva) no escopo do arquivo em um arquivo / cabeçalho de inclusão! Isso causará dores de cabeça para os usuários do cabeçalho.
Michael Burr
Na verdade, não colocar uma usingdeclaração (a fortiori directiva ) em um cabeçalho em tudo , mesmo dentro de um namespace! Consulte o escopo do uso da declaração em um namespace para ver os problemas que isso causa.
Nils von Barth
@NilsvonBarth: Isso é um pouco simplificado. Usar o usingescopo de classe e função é seguro em relação ao problema discutido.
Sebastian Mach,
Você pode estar interessado em ler sobre o recurso de pesquisa ADL C ++ .
Alexis Wilke

Respostas:

59

Quando você #inclui um arquivo de cabeçalho em C ++, ele coloca todo o conteúdo do arquivo de cabeçalho no local em que você o incluiu no arquivo de origem. Portanto, incluir um arquivo que possui uma usingdeclaração tem exatamente o mesmo efeito de colocar a usingdeclaração no topo de cada arquivo que inclui esse arquivo de cabeçalho.

Jeremy Ruten
fonte
51
... o que geralmente é uma coisa ruim.
Catskul
17
Mas se você colocar a usingdeclaração dentro de um, namespaceela estará limitada ao escopo daquele namespace, então geralmente está OK (com as advertências usuais sobre suas necessidades e estilo específicos).
Zero
1
... mas se você colocar using dentro de um namespace, certifique-se de não fazer isso para tentar contornar algo que normalmente é uma má ideia, como você não pode encerrar métodos de classe declarados fora do namespace Y dentro de outro namespace X, apenas para que você possa usar localmente o namespace X. É por isso que usamos namespace :: resolvers em primeiro lugar. Se for um grande problema de digitação, uma macro (que pode facilmente levar a cheiros de código) ou melhor ainda, isole-a em seu próprio código-fonte .cpp, onde você usará o namespace lá apenas.
osirisgothra
1
Embora esta e outras respostas semelhantes sejam bons conselhos, eles não respondem à pergunta.
Emile Cormier
116

Não há nada de especial nos arquivos de cabeçalho que impeçam a usingdeclaração. É uma simples substituição de texto antes mesmo de começar a compilação.

Você pode limitar uma usingdeclaração a um escopo:

void myFunction()
{
   using namespace std; // only applies to the function's scope
   vector<int> myVector;
}
Eclipse
fonte
12
Nunca pensei que poderia usá-lo dentro de uma função!
Agostino
1
Eu tenho um monte de namespaces sendo usados ​​por um arquivo do tipo "conglomerador", e o teste de unidade gmock era extremamente tedioso porque cada teste usava coisas de um namespace específico e eu pensei que tinha que qualificar cada variável. Usar usingdentro de uma função (ou mesmo uma TESTmacro gtest !) Torna minha vida muito melhor!
dwanderson
54

O escopo da instrução using depende de onde ela está localizada no código:

  • Colocado no topo de um arquivo, tem escopo em todo o arquivo.
  • Se este for um arquivo de cabeçalho, ele terá escopo em todos os arquivos que incluem esse cabeçalho. Em geral, esta " não é uma boa ideia ", pois pode ter efeitos colaterais inesperados
  • Caso contrário, a instrução using tem escopo dentro do bloco que a contém desde o ponto em que ocorre até o final do bloco. Se for colocado dentro de um método, terá escopo dentro desse método. Se for colocado dentro de uma definição de classe, terá escopo dentro dessa classe.
dagorym
fonte
5
Achei que não fosse possível adicionar uma usinginstrução dentro do escopo da classe ...? Eu tive a mesma pergunta que o OP por causa disso, porque eu queria evitar digitar em std::todo lugar. Eu tenho classes que usam muitos vetores com ponteiros inteligentes e o std::prefixo de cinco caracteres adiciona muito comprimento de linha - o que eu acho pior. Então, eu queria saber se uma usingdiretiva dentro do namespace contendo a classe estava ok? (Mesmo se dentro de um cabeçalho.)
thomthom
5
E se for colocado dentro do escopo de um namespace { ... }?
einpoklum de
Assim, você pode escrever totalmente: {using namespace blabla; classe blah {}; } e esse uso só se aplicará à aula?
Dinaiz 01 de
8

O escopo é qualquer escopo em que a declaração de uso esteja.

Se for um escopo global, então será no escopo global. Se estiver no escopo global de um arquivo de cabeçalho, ele estará no escopo global de todos os arquivos de origem que incluem o cabeçalho.

Portanto, o conselho geral é evitar o uso de declarações no escopo global de arquivos de cabeçalho .

JohnMcG
fonte
3
Isso não é forte o suficiente. Substitua evitar por Não
Martin York,
1
Mas evitar é mais forte do que não fazer. "Evite bater nos outros carros"
bobobobo
6

No caso citado, o arquivo (“unidade de tradução”), ou seja, todo arquivo que o contenha.

Você também pode colocar a instrução using dentro da classe; nesse caso, ela está em vigor apenas para aquela classe.

Geralmente, se você precisa especificar um namespace em um cabeçalho, geralmente é melhor apenas qualificar totalmente cada identificador necessário.

James Curran
fonte
Observe que a usingdeclaração em uma classe não se comporta da mesma maneira que fora de uma classe - por exemplo, você não pode usá-la para trazer em coutvez de std::coutpara o escopo da classe.
Zero
2

Está correto. O escopo é o módulo que usa a usingdeclaração. Se qualquer arquivo de cabeçalho que um módulo inclui tiver usingdeclarações, o escopo dessas declarações será aquele módulo, bem como quaisquer outros módulos que incluam os mesmos cabeçalhos.

Ates Goral
fonte
1

Existem alguns comentários que não são qualificados quando dizem "Não". Isso é muito severo, mas você tem que entender quando está OK.

Escrever using std::stringnunca está bem. Escrever using ImplementationDetail::Fooem seu próprio cabeçalho, quando esse cabeçalho declara ImplementationDetail :: Foo pode ser OK, ainda mais se a declaração de uso acontecer em seu namespace. Por exemplo

namespace MyNS {
    namespace ImplementationDetail {
        int Foo;
    }
    using ImplementationDetail::Foo;
}
MSalters
fonte
1
O usuário do cabeçalho pode escreverMyNS::Foo
Peter Remmers
Um exemplo melhor é using boost::posix_time::ptime. Claro que o usuário poderia escrever, MyNS::ptimemas isso não é o fim do mundo e pode ser compensado pela conveniência de poder ter funções como MyFunction(ptime a, ptime b).
Zero
5
Por queusing std::string nunca está bem? Mesmo em seu próprio namespace para salvar muitos std::prefixos?
thomthom
@ thomthom está tudo bem quando agrupado em um escopo como seu próprio namespace.
jcoffland