В С++ 14, в какой области объявлены незарегистрированные счетчики объявленных деклараций?

С++ 14 (точно, N4296) говорит относительно перечислений, в 7.2: 11:

Каждое имя перечисления и каждый неперечисленный счетчик объявляются в области который немедленно содержит спецификатор перечисления.

Теперь, что произойдет, если пространство имен N содержит непрозрачное enum-объявление перечисления E, а позже перечисление полностью объявлено из глобального пространства имен? Должны ли мы найти его перечисления в глобальном пространстве имен или в пространстве имен N?

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

namespace N { enum E : int; }
enum N::E : int {A,B};

namespace N {
    int foo() {
        return int(::N::B);
    }
}

int bar() {
    //return int(::A);
    return int(A);
}

Первая строка в bar закомментирована, потому что clang++ -std=c++14 говорит:

нет члена с именем 'A' в глобальном пространстве имен; вы имели в виду просто "А"?

Gcc не может скомпилировать обе строки в bar(). Таким образом, gcc и clang объявляют перечисления в пространстве имен N.

Итак, мои вопросы:

  • Какова область действия, которая непосредственно содержит спецификатор перечисления? (Я считаю, что это область глобального пространства имен).
  • Если в глобальном пространстве имен должны быть определены счетчики A, B?
  • В функции bar, почему ::A не ссылается на перечислитель, но простой A делает?
  • Почему выражение ::N::B в функции N::foo обозначает перечислитель?

EDIT 1: оригинальное объявление было enum ::N::E : int {A,B};, но gcc не смог его разобрать (отчет об ошибке), поэтому я удалил ведущие двоеточия использовать enum N::E : int {A,B};

EDIT 2: поведение clang bug

Ответы

Ответ 1

Перечисление E объявляется в пространстве имен N, хотя его определение задано в глобальном пространстве имен. Таким образом, доступ к нему возможен только в области N.

Затем функцию бара следует определять как:

int bar() {
    return int(N::A);
    //SAME AS --> return int(::N::A);
}