пространства имен, имеющие безымянное пространство имен с той же объявленной переменной - PullRequest
7 голосов
/ 02 декабря 2011

Я попробовал этот фиктивный код ниже для проверки безымянного пространства имен.

У меня есть следующий вывод

 ctor 1
 ctor 0
 3
 5

Я немного смущен по этому поводу.* Я ожидал ошибки от компилятора, который сказал, что он не может разрешить неоднозначность относительно a::m_a.Вместо этого это всегда относится к менее вложенным.Это всегда так?Каким правилам следует C ++?

Похоже, что компилятор создает переменную CMyObj в порядке, указанном в файле.Всегда ли это так? есть ли способ получить доступ к самой вложенной переменной m_a из main() ?.
class CMyObj{     
    public:
    CMyObj(int a){std::cout  << "ctor " << a << std::endl; }
 };
 namespace a{ 
      namespace{
           int m_a=4;
           int m_b=5;
           CMyObj m_obj(1);
      }  
 }
 namespace a{
      int m_a=3;
      CMyObj m_obj(0);
 }
 int main(){
      std::cout << a::m_a << std::endl; // which one?
      std::cout << a::m_b << std::endl; // how this is possible?
      return 0;
 }

Ответы [ 4 ]

3 голосов
/ 02 декабря 2011

У меня нет стандарта C ++ 03, чтобы проверить там формулировку, поэтому я приведу цитату из FDIS n3290.Я думаю, что ответ на этот вопрос можно найти в квалифицированных правилах поиска имен в 3.4.3.2/2:

Для пространства имен X и имени m, квалифицированный набор поиска пространства имен S (X, m)определяется следующим образом: пусть S0 (X, m) будет множеством всех объявлений m в X и множеством встроенных пространств имен X (7.3.1).Если S0 (X, m) не пусто, то S (X, m) равно S0 (X, m);в противном случае S (X, m) является объединением S (Ni, m) для всех пространств имен Ni, назначенных с помощью директив using в X и его встроенном наборе пространств имен.

Теперь запомните это безымянное пространство именявляется пространством имен с уникальным именем и директивой using.

1 голос
/ 02 декабря 2011

Сначала посмотрите на этот упрощенный код (и мое упрощенное объяснение, вы можете прочитать §3.4.3.2 для деталей):

namespace a
{
    int x;
}

int main()
{
    int i = a::x;
}

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

namespace a
{
    int x;
}

namespace b
{
    using namespace a;
}

int main()
{
    int i = b::x;
}

Здесь он не находит x в b, поэтому он ищет пространство имен a (из-за директивы using) и находит его. Теперь должно иметь смысл, почему это не является двусмысленным:

namespace a
{
    int x;
}

namespace b
{
    using namespace a;
    int x;
}

int main()
{
    int i = b::x;
}

Здесь он находит x в b и никогда не рассматривает a. Теперь просто учтите, что безымянное пространство имен - это просто пространство имен с уникальным неизвестным именем:

namespace b
{
    namespace
    {
        int x;
    }

    // this is what an unnamed namespace expands to (in exposition)
    namespace __unique__ {}
    using namespace __unique__;

    namespace __unique__
    {
        int x;
    }

    int x;
}

int main()
{
    int i = b::x;
}

Как и прежде, x в b находится без учета безымянного пространства имен. Ваш код похож.

1 голос
/ 02 декабря 2011

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

a::m_b 

во втором операторе std::cout, компилятор автоматически подставляет искаженное имя, чтобы вы могли получить к нему доступ.Включая из последующего ответа Джина Бушуева:

Теперь запомните, что безымянное пространство имен - это пространство имен с уникальным именем и директивой using.

В случае встречающихся имен,Компилятор знает, что означает a::m_a, поэтому он использует это.Это один на верхнем уровне пространства имен.Я не думаю, что есть какой-либо способ добраться до безымянной копии пространства имен m_a на данный момент.

Эта страница неплохо объясняет пространства имен. Winterdom: на пространствах имен C ++

0 голосов
/ 02 декабря 2011

Не существует двусмысленности, поскольку область действия namespace::<unnamed>::m_a является внешним пространством имен (namespace::a). Нет доступа к namespace::<unnamed>::m_a в основной функции, поэтому нет никакой двусмысленности. Попробуйте скомпилировать следующий код, и вы получите ошибку:

namespace ns{
  namespace {
    int a = 2;
  }
  int a = 3;
  int c = a;
}

Глобальные переменные, находящиеся в одной и той же единице перевода, будут инициализированы в порядке их объявления. Порядок инициализации глобальных переменных, объявленных в разных единицах перевода, не определен.

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