Pytanie Czy używanie przestrzeni nazw powoduje ukrywanie nazwy?


Rozważ następujący kod:

namespace C {
    class X {};
}

namespace A {
    class X {};

    namespace B {
        using namespace C;

        X x;
    }
}

Spodziewałem się rodzaju x być C::X z powodu using namespace dyrektywy, ale zamiast tego obu VS2010 i online LLVM / Clang rozwiązywanie kompilatora X w przestrzeni nazw B być A::X. Zmiana dyrektywy use z deklaracją użycia (using C::X), to rozwiązuje się C::X zgodnie z oczekiwaniami.

Standard mówi o zastosowaniu dyrektyw [7.3.4.2]:

Dyrektywa using określa, że ​​nazwy w wyznaczonym obszarze nazw mogą być używane w zakresie, w którym dyrektywa use pojawia się po użyciu dyrektywy. Podczas niewykwalifikowanego wyszukiwania nazw (3.4.1) nazwy wyglądają tak, jakby były zadeklarowane w najbliższej otaczającej przestrzeni nazw, która zawiera zarówno dyrektywę użycia, jak i nazwaną przestrzeń nazw.

Czytałem o tym C::X powinien wyglądać tak, jakby był zadeklarowany w przestrzeni nazw B, skutecznie ukrywając się A::X. Które odcinki normy stoją za tą sprzecznością między stosowaniem dyrektyw a wykorzystaniem deklaracji? Czy istnieje sposób na ukrycie nazwy z zewnętrznego zakresu za pomocą dyrektywy using?


12
2018-05-24 16:20


pochodzenie


Może wskazówka jest w środku nazwy pojawiają się tak, jakby były zadeklarowane w najbliższej otaczającej przestrzeni nazw, która zawiera obie dyrektywa użytkowa i wyznaczona przestrzeń nazw. Czy nie byłoby ::? A jeśli tak, to A::X nie można go znaleźć jako pierwszego (wyszukiwanie pochodzi z wewnętrznej przestrzeni nazw) ... nie jest to jednak pewne, ale g ++ także pobiera dane A::Xtak jest bardzo spójny w różnych kompilatorach. - David Rodríguez - dribeas
@David Rodríguez - dribeas: Oh, to by to wyjaśniło ... - K-ballo


Odpowiedzi:


Rozdział na temat za pomocą dyrektywy wydaje się jakoś jasne, że widzisz oczekiwane zachowanie:

7.3.4p2 Dyrektywa using określa, że ​​nazwy w wyznaczonym obszarze nazw mogą być używane w zakresie, w którym dyrektywa use pojawia się po użyciu dyrektywy. Podczas niewykwalifikowanego wyszukiwania nazw (3.4.1) nazwy wyglądają tak, jakby były zadeklarowane w najbliższej otaczającej przestrzeni nazw, która zawiera obie dyrektywa użytkowa i wyznaczona przestrzeń nazw.

7.3.4p3 Dyrektywa użycia nie dodaje żadnych członków do regionu deklaratywnego, w którym się pojawia.

To jest użycie dyrektywy dodaje członków obszaru nazw do zestawu odnośników wspólnego przodka przestrzeni nazw dyrektywy i używanego obszaru nazw, a nie bezpośrednio do zakresu, w którym użycie dyrektywy Jest używane. Jest to wyraźnie określone w drugim cytacie: nie dodaje żadnych członków do deklaratywnego regionu użycie dyrektywy.

Później jest przykład, który ma ilustrować coś innego, ale faktycznie pokazuje to:

7.3.4p4 [...] Dla innego przykładu

namespace A {
  int i;
}
namespace B {
  int i;
  int j;
  namespace C {
    namespace D {
      using namespace A;
      int j;
      int k;
      int a = i; // B::i hides A::i
    }

Ten ostatni przykład służy do wyjaśnienia przechodniości (i zawiera więcej kodu), ale w rzeczywistości jest to odpowiednik twojego kodu po usunięciu dodatkowego kodu.

Wygląda więc na to, że w twoim przypadku użycie dyrektywy nie ukrywa się, ale raczej jest ukryty.


6
2018-05-24 16:39



Więc na moje drugie pytanie, zakładam to jest możliwe ukrywanie nazw za pomocą dyrektyw, ale tylko wtedy, gdy znajdują się w zewnętrznym obszarze wspólnego przodka przestrzeni nazw. - K-ballo
Tak bym powiedział. W każdym razie uniknęłbym tego dyrektywy użytkowe całkowicie i tylko używaj deklaracje użycia rzadko. Wyszukiwanie staje się o wiele bardziej skomplikowane i trudniej jest określić, co dokładnie jest używane, gdzie jest zdefiniowane ... Jeśli potrzebujesz spłaszczenia, użyj złożonych zagnieżdżonych przestrzeni nazw, rozważ aliasy przestrzeni nazw. - David Rodríguez - dribeas
Ja unikam dyrektywy użytkowe w moim prawdziwym kodzie jest to po prostu próba "znalezienia miejsca, w którym żyje klasa" poprzez zastosowanie reguł wyszukiwania nazw. - K-ballo