Неопределенность Анонимного Пространства Имен


Рассмотрим следующий фрагмент:

void Foo() // 1
{
}

namespace
{
  void Foo() // 2
  {
  }
}

int main()
{
  Foo(); // Ambiguous.
  ::Foo(); // Calls the Foo in the global namespace (Foo #1).

  // I'm trying to call the `Foo` that's defined in the anonymous namespace (Foo #2).
}

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

5 17

5 ответов:

Вы не можете. стандарт содержит следующий раздел (§7.3.1.1, C++03):

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

  namespace unique { /* empty body */ }
  using namespace unique;
  namespace unique { namespace-body }

Где все вхождения единственного в единицы перевода заменяются на тот же идентификатор и этот идентификатор отличается от всех других идентификаторов во всей программе.

Таким образом, у вас нет возможности ссылаться на это уникальное имя.

Вы могли бы, однако, технически использовать вместо этого что-то вроде следующего:

int i;

namespace helper {
    namespace {
        int i;
        int j;
    }
}

using namespace helper;

void f() { 
    j++; // works
    i++; // still ambigous
    ::i++; // access to global namespace
    helper::i++; // access to unnamed namespace        
}

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

#include <iostream>

using namespace std;

namespace
{
namespace inner
{
    int cout = 42;
}
}

int main()
{
    cout << inner::cout << endl;
    return 0;
}

Единственное решение, которое я могу придумать, которое не изменяет существующую структуру пространства имен, - это делегировать main функции в анонимном пространстве имен. (main Сама по себе должна быть глобальной функцией (§3.6.1/1), поэтому она не может находиться в анонимном пространстве имен.)

void Foo() // 1
{
}

namespace
{
  void Foo() // 2
  {
  }
}

namespace { // re-open same anonymous namespace

    int do_main()
    {
      Foo(); // Calls local, anonymous namespace (Foo #2).
      ::Foo(); // Calls the Foo in the global namespace (Foo #1).

      return 0; // return not optional
    }

}

int main() {
    return do_main();
}

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

Если ваш код находится внутри самого блока пространства имен {}, локальное имя получает приоритет над глобальным, поэтому Foo () вызовет Foo () в вашем пространстве имен, а a ::Foo() вызовет пространство имен в глобальной области.

Просто переименуйте функцию локального пространства имен.