2014-12-11 6 views
10

У меня есть этот пример кодас использованием директивы - почему так странное поведение?

namespace ns1 
{ 
    void foo(int) 
    { 
    } 
} 

namespace ns2 
{ 
    void foo() 
    { 
    } 
    void bar() 
    { 
     using namespace ::ns1; 
     foo(42); // why compiler can't just call ns1::foo? 
    } 
} 

И это не компилируется с ошибкой:

prog.cpp:16:9: error: too many arguments to function ‘void ns2::foo()’ 

Я нашел причину этой ошибки в стандарте C++ 2003:

A using-directive specifies that the names in the nominated namespace can be used in the scope in which the using-directive appears after the using-directive. During unqualified name lookup (3.4.1), the names appear as if they were declared in the nearest enclosing namespace which contains both the using-directive and the nominated namespace. [Note: in this context, “contains” means “contains directly or indirectly”. ]

какие-либо Обоснование за это странное правило? Почему имена из пространства имен ns1 не могут непосредственно отображаться в пространстве имен ns2?

+0

Поскольку я никогда не видел, чтобы «использование» использовалось таким образом, я рискну предположить. Он пытается вывести имя в текущее пространство имен и, вероятно, не так, как вы намереваетесь входить только в контекст функции. Вероятно, столкновение двух функций является проблемой. – Photon

+0

Вы даете компилятору выбор, как ns1 :: foo, так и ns2 :: foo в области. Какой, по-вашему, он должен выбрать? Ближайший или самый дальний? Вам нравится, когда компилятор выбирает глобальную переменную с тем же именем, что и параметр функции? И если вы скажете «ns1 :: foo, конечно!» то почему бы просто не написать так? –

+0

Согласно D & E, используемые директивы «дают имена доступным». Поскольку мы (потенциально) не знаем, что полный набор имен стал доступным, он более консервативен и помещает их дальше в иерархию пространства имен (чтобы они не случайно скрывали имена). Ближайшее охватывающее пространство имен может интерпретироваться как общая часть программы; что-либо заключенное менее специализировано, все заключенное является более специализированным и поэтому должно иметь приоритет. Но я просто догадываюсь. – dyp

ответ

9

Я считаю, что это было/сделано в попытке уменьшить конфликты и сюрпризы. Имена, введенные в область действия с помощью директивы using, видны, но все, что непосредственно содержится в локальной области, будет иметь приоритет над ней.

Если вы действительно хотите, чтобы позвонить вам работать без квалифицированного ID, вы сделать его видимым с using декларации вместо:

namespace ns1 { 
    void foo(int) { } 
} 

namespace ns2 { 
    void foo() { } 
    void bar() { 
     using ::ns1::foo; 
     foo(42); // No problem; calls ::ns1::foo. 
    } 
} 
+0

Я знаю о возможности использования использования объявления, но вопрос именно об использовании директивы. –

+0

@maxim.yurchuk: Да, именно поэтому я сначала ответил на вопрос о директиве 'use', и только однажды я сделал эту дополнительную информацию об одном возможном обходном пути. –

+0

о сокращении конфликтов и сюрпризов: Я думаю, что этот пример: https://ideone.com/qdGaCC довольно удивителен. –

2

ns1::foo в настоящее время скрытой декларации о ns2::foo

С N3337, §3.3.10/1[basic.scope.hiding]

A name can be hidden by an explicit declaration of that same name in a nested declarative region or derived class (10.2).

В разделе вы цитируемый (§7.3.4/2) немедленно следует

3   A using-directive does not add any members to the declarative region in which it appears. [ Example:

namespace A { 
     int i; 
     namespace B { 
     namespace C { 
      int i; 
     } 
     using namespace A::B::C; 
     void f1() { 
      i = 5; // OK, C::i visible in B and hides A::i 
     } 
     } 
     // more (irrelevant) stuff 
    } 

—end example ]

В вашем случае с помощью директивы вводит имена в ns1 к общему предку пространство имен, где оно появляется, и пространство ns1, что означает глобальное пространство имен. Он не вводит их в пределах ns2, поэтому декларация ns2::foo скрывает от ns1::foo.

Если вы хотите, чтобы ns1::foo был найден, используйте вместо него вместо этого используемую декларацию.

void bar() 
{ 
    using ::ns1::foo; 
    foo(42); 
} 
+0

Я знаю эти факты, и я понимаю, почему этот код не компилируется. Я спросил об объяснении этих правил: почему использование декларации вводит имена в область видимости, но с помощью директивы нет? –

+0

@ maxim.yurchuk Это * описание * правил. Если вы смотрите * обоснование *, почему они работают таким образом, тогда ответ Джерри Коффина может быть тем, кого вы ищете. Я не знаю другой причины. – Praetorian

+0

спасибо, я заменю «объяснение» на «обоснование» в вопросе. –

Смежные вопросы