class C {
using namespace std; // error
};
namespace N {
using namespace std; // ok
}
int main () {
using namespace std; // ok
}
Edit : Quer saber a motivação por trás disso.
c++
namespaces
using
language-lawyer
iammilind
fonte
fonte
using namespace
. C # permite algo semelhante, mas apenas no escopo do arquivo. O C ++using namespace
permite que você incorpore um namespace a outro.class/struct
. Simplesmente não é permitido. Mas a resposta aceita discute uma justificativa muito lógica para rejeitá-la. ou seja, onde considerarHello::World
e onde considerarWorld
. Espero que isso esclareça a dúvida.Respostas:
Não sei exatamente, mas meu palpite é que permitir isso no escopo da classe pode causar confusão:
namespace Hello { typedef int World; } class Blah { using namespace Hello; public: World DoSomething(); } //Should this be just World or Hello::World ? World Blah::DoSomething() { //Is the using namespace valid in here? }
Como não há uma maneira óbvia de fazer isso, o padrão apenas diz que você não pode.
Agora, o motivo disso é menos confuso quando estamos falando de escopos de namespace:
namespace Hello { typedef int World; } namespace Other { using namespace Hello; World DoSomething(); } //We are outside of any namespace, so we have to fully qualify everything. Therefore either of these are correct: //Hello was imported into Other, so everything that was in Hello is also in Other. Therefore this is okay: Other::World Other::DoSomething() { //We're outside of a namespace; obviously the using namespace doesn't apply here. //EDIT: Apparently I was wrong about that... see comments. } //The original type was Hello::World, so this is okay too. Hello::World Other::DoSomething() { //Ditto } namespace Other { //namespace Hello has been imported into Other, and we are inside Other, so therefore we never need to qualify anything from Hello. //Therefore this is unambiguiously right World DoSomething() { //We're inside the namespace, obviously the using namespace does apply here. } }
fonte
using namespace Hello;
dentro de outronamespace
também (e declararextern
função dentro dele).Hello::World Blah::DoSomething()
ouBlah::World Blah::DoSomething()
(se permitido), o tipo de retorno de uma definição de função de membro não é considerado no escopo da classe na linguagem, portanto, deve ser qualificado. Considere o exemplo válido de substituição deusing
por umtypedef Hello::World World;
no escopo da classe. Portanto, não deve haver surpresas aí.Porque o padrão C ++ proíbe explicitamente isso. De C ++ 03 §7.3.4 [namespace.udir]:
Por que o padrão C ++ o proíbe? Não sei, pergunte a um membro do comitê ISO que aprovou o padrão de idioma.
fonte
Eu acredito que o raciocínio é que provavelmente seria confuso. Atualmente, ao processar um identificador de nível de classe, a pesquisa pesquisará primeiro no escopo da classe e, em seguida, no namespace delimitador. Permitir o
using namespace
em nível de classe teria alguns efeitos colaterais sobre como a pesquisa agora é realizada. Em particular, ele teria que ser executado em algum momento entre a verificação do escopo da classe em particular e a verificação do namespace envolvente. Isto é: 1) mesclar o nível de classe e as pesquisas de nível de namespace usado, 2) pesquisar o namespace usado após o escopo da classe, mas antes de qualquer outro escopo de classe, 3) pesquisar o namespace usado antes do namespace delimitador. 4) lookup mesclado com o namespace delimitador..
namespace A { void foo() {} struct B { struct foo {}; void f() { foo(); // value initialize a A::B::foo object (current behavior) } }; } struct C { using namespace A; struct foo {}; void f() { foo(); // call A::foo } };
.
namespace A { void foo() {} } void bar() {} struct base { void foo(); void bar(); }; struct test : base { using namespace A; void f() { foo(); // A::foo() bar(); // base::bar() } };
.
namespace A { void foo( int ) { std::cout << "int"; } } void foo( double ) { std::cout << "double"; } struct test { using namespace A; void f() { foo( 5.0 ); // would print "int" if A is checked *before* the // enclosing namespace } };
using
declaração no nível do namespace. Isso não adicionaria nenhum valor novo a isso, mas, por outro lado, complicaria a pesquisa de implementadores de compilador. A pesquisa do identificador de namespace agora é independente de onde no código a pesquisa é acionada. Quando dentro de uma classe, se a pesquisa não encontrar o identificador no escopo da classe, ela retornará à pesquisa de espaço de nomes, mas essa é exatamente a mesma pesquisa de espaço de nomes usada em uma definição de função, não há necessidade de manter o novo estado. Quando ausing
declaração é encontrada no nível do namespace, o conteúdo do namespace usado é trazido para esse namespace para todas as pesquisas envolvendo o namespace. E seusing namespace
fosse permitido no nível de classe, haveria resultados diferentes para a pesquisa de namespace do mesmo namespace, dependendo de onde a pesquisa foi disparada, e isso tornaria a implementação da pesquisa muito mais complexa sem nenhum valor adicional.De qualquer forma, minha recomendação é não usar a
using namespace
declaração de forma alguma. Ele torna o código mais simples de raciocinar, sem ter que manter todos os conteúdos dos namespaces em mente.fonte
using
existe. Declarando coisas propositalmente em namespaces longos aninhados. Por exemplo,glm
faz isso e usa vários truques para ativar / apresentar recursos quando o cliente usausing
.using namespace std::placeholders
. cf en.cppreference.com/w/cpp/utility/functional/bindnamespace ph = std::placeholders;
Isso provavelmente não é permitido por causa da abertura versus fechamento.
Importar namespaces para classes levaria a casos engraçados como este:
namespace Foo {} struct Bar { using namespace Foo; }; namespace Foo { using Baz = int; // I've just extended `Bar` with a type alias! void baz(); // I've just extended `Bar` with what looks like a static function! // etc. }
fonte
namespace Foo
à ordem de pesquisa para todo o código dentro da definição de tipo destruct Bar
, de forma muito semelhante a colocar essa linha em cada corpo de função de membro embutido, exceto que também estaria ativo para inicializadores de chave ou igual, etc. Mas ainda estaria expira na chave de fechamento, o mesmo queusing namespace
dentro do corpo de uma função de membro. Agora, infelizmente, não parece haver nenhuma maneira de usar a pesquisa Koenig-com-fallback em um inicializador de chave ou igual sem poluir o namespace delimitador.Acho que é um defeito da linguagem. Você pode usar a solução alternativa abaixo. Tendo em mente essa solução alternativa, é fácil sugerir regras de resolução de conflitos de nomes para o caso em que o idioma será alterado.
namespace Hello { typedef int World; } // surround the class (where we want to use namespace Hello) // by auxiliary namespace (but don't use anonymous namespaces in h-files) namespace Blah_namesp { using namespace Hello; class Blah { public: World DoSomething1(); World DoSomething2(); World DoSomething3(); }; World Blah::DoSomething1() { } } // namespace Blah_namesp // "extract" class from auxiliary namespace using Blah_namesp::Blah; Hello::World Blah::DoSomething2() { } auto Blah::DoSomething3() -> World { }
fonte