2012-05-24 2 views
12

Рассмотрим следующий код:Является ли использование пространства имен причиной скрытия имени?

namespace C { 
    class X {}; 
} 

namespace A { 
    class X {}; 

    namespace B { 
     using namespace C; 

     X x; 
    } 
} 

Я ожидал, что тип x быть C::X вследствие using namespace директивы, но вместо того, чтобы как VS2010 и онлайн LLVM/Clang компилятор решительность X в пространстве имен BA::X. Изменение директивы using с использованием объявления (using C::X), то оно действительно принимает C::X, как и ожидалось.

Стандарт говорит об использовании директив [7.3.4.2]:

А с использованием директивы указывает, что имена в выдвинутого имен могут быть использованы в объеме, в котором с помощью директивы появляется после использования -directive. При неквалифицированном поиске имени (3.4.1) имена отображаются так, как если бы они были объявлены в ближайшем охватывающем пространстве имен, которое содержит как директиву-по умолчанию, так и назначенное пространство имен.

Мое чтение этого является то, что C::X должно появиться, если объявленная в пространстве имен B, эффективно скрывая A::X. Какой раздел (ы) стандарта находится за этой несогласованностью между использованием директив и использованием деклараций? Есть ли способ скрыть имя из внешней области с помощью директивы using?

+5

Возможно, ключ находится в * именах, как если бы они были объявлены в ближайшем охватывающем пространстве имен, которое содержит ** как ** директиву использования, так и номинированное пространство имен *. Не будет ли это '::'? И если это так, сначала будет обнаружен «A :: X» (поиск происходит из внутреннего пространства имен) ... но не уверен, но g ++ также делает «A :: X», поэтому он очень * согласованный между компиляторами. –

+0

@David Rodríguez - dribeas: О, это объяснило бы это ... –

ответ

6

В главе о , используя директиву, кажется, как-то ясно, что вы видите ожидаемое поведение:

7.3.4p2 А с использованием директивы указывает, что имена в выдвинутого имен могут быть использованы в области, в которой появляется директива using после директивы use. При поиске неквалифицированного имени (3.4.1) имена отображаются так, как если бы они были объявлены в ближайшем охватывающем пространстве имен, которое содержит как, так и назначенное пространство имен.

7.3.4p3 Директива-указатель не добавляет никаких членов в декларативную область, в которой она появляется.

То есть, с помощью директивы добавляет членов пространства имен к перекодировки набора общего пространства имен предка директивы и используемого пространства имен, а не непосредственно к объему, где используя директиву используется. Это явно указано во второй цитате: она не добавляет никаких членов в декларативную область с использованием директивы.

Позже есть пример, который предназначен для иллюстрации что-то другое, но на самом деле это показывает:

7.3.4p4 [...] В другом примере

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 
    } 

Этот последний пример используется для уточнения транзитивности (и содержит больше кода), но на самом деле он эквивалентен вашему коду после удаления дополнительного кода.

Похоже, что в вашем случае с использованием директивы не скрывается, а скорее скрывается.

+0

Итак, для моего второго вопроса, я предполагаю, что ** возможно скрыть имена с помощью директив, но только если они находятся во внешней области общего предка пространства имен. –

+0

Я бы так сказал. Во всяком случае, я бы вообще избегал * использования-директив * и редко использовал * using-declarations * редко. Поиск просто становится намного сложнее, и сложнее определить, что именно используется, где оно определено ... Если ваша необходимость сглаживает использование сложных вложенных пространств имен, рассмотрите * псевдонимы пространства имен *. –

+0

Я избегаю _using-directives_ в моем реальном коде, это всего лишь попытка «найти, где живет класс», используя правила поиска имен. –