Вложение безымянных пространств имен - PullRequest
15 голосов
/ 15 июня 2011

Есть ли функциональная разница между этими двумя вложенными использованиями безымянных пространств имен:

namespace A { namespace {
  void foo() {/*...*/}
}}

и

namespace { namespace A {
  void foo() {/*...*/}
}}}

Насколько я вижу, оба foo s получатвнутренний уникальный идентификатор для каждой единицы компиляции, к которому можно получить доступ с помощью A::foo - но есть ли тонкое или не очень тонкое различие, которого я не вижу?

1 Ответ

7 голосов
/ 16 июня 2011

Точно так же, как вы набрали, нет никакой разницы.

Конечно, вы можете добавить объявления на первом уровне пространства имен в примеры стендов, и тогда будет различие.

namespace A {
  int i;         // Accessed globally in this file as "A::i".
  namespace {
    void foo() {/*...*/}
}}


namespace {
  int i;         // Accessed globally in this file simply as "i".
  namespace A {
    void foo() {/*...*/}
}}}

Обратите внимание, что, хотя вы, программист, не можете различить, для компилятора пространства имен различны:

unnamed_namespaces.cpp:42:5: error: reference to ‘A’ is ambiguous
unnamed_namespaces.cpp:19:17: error: candidates are: namespace A { }
unnamed_namespaces.cpp:28:19: error:                 namespace <unnamed>::A { }

Usefull:


EDIT:

Что касается ADL (поиск имени в зависимости от аргумента), я понимаю, что не будет разницы в приоритетах в разрешении перегрузки для других foo(), как показано ниже:

#include    <iostream>

void foo() { std::cout << "::foo()" << std::endl; }

namespace A {
    namespace {
        void foo() { std::cout << "A::<unnamed>::foo()" << std::endl; }

        class   AClass
        {
        public:
            AClass( )
            {   foo( ); }
        };
    }
}


namespace {
    namespace B {
        void foo() { std::cout << "B::<unnamed>::foo()" << std::endl; }

        using namespace A;

        class   BClass
        {
        public:
            BClass( )
            {   foo( ); }

            ~BClass( )
            {   A::foo( );  }
        };
    }
}

int main( )
{
    A::foo( );
    B::foo( );
    foo( );

    A::AClass   a;
    B::BClass   b;

    return  0;
}

Компилятор предпочтет ближайший foo( ), если это не указано явно. Итак, конструктор BClass вызывает B::foo( ), даже имея using namespace A. Для вызова A::foo( ) на деструкторе BClass вызов должен быть явно указан.

A::<unnamed>::foo()
B::<unnamed>::foo()
::foo()
A::<unnamed>::foo()
B::<unnamed>::foo()
A::<unnamed>::foo()

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...