Является ли "typename" разрешенным/обязательным в С++ 11 using-declaration? - программирование

Является ли "typename" разрешенным/обязательным в С++ 11 using-declaration?

Следующий код компилируется правильно в g++ и clang:

template<typename T>
struct foo
{
    class iterator;
    using bar = foo::iterator;
};

int main() {}

однако MSVC 2013 дает следующие ошибки:

foo.cpp(9): error C2061: syntax error : identifier 'iterator'
          foo.cpp(10) : see reference to class template instantiation 'foo<T>' being compiled
foo.cpp(9): error C2238: unexpected token(s) preceding ';'

Если я изменил эту строку на:

using bar = typename foo::iterator;

то все три компилятора скомпилируют его успешно. Верна ли исходная версия? (т.е. это ошибка MSVC или расширение gcc/clang)

4b9b3361

Ответ 1

[temp.res]/р3:

Когда квалифицированный идентификатор предназначен для обозначения типа, который не является член текущего экземпляра (14.6.2.1) и его inested-name-specifier ссылается на зависимый тип, он должен быть префикс с ключевым словом typename, формируя спецификатор-имя-тип.

[temp.dep.type]/р1:

Имя относится к текущему экземпляру, если оно

  • в определении шаблона класса, вложенного класса шаблона класса, члена шаблона класса или члена вложенного класса шаблона класса, имя введенного класса (раздел 9) класса шаблон или вложенный класс,
  • [...]

[temp.dep.type]/р4:

Имя является членом текущего экземпляра, если оно

  • Неквалифицированное имя, которое при просмотре относится к хотя бы одному члену класса, который является текущим экземпляром или не зависящим от него его базовый класс. [Примечание. Это может произойти только при поиске имя в области, охватываемой определением шаблона класса. -конец примечание]
  • Квалифицированный идентификатор, в котором спецификатор вложенных имен ссылается на текущий экземпляр, и который при поиске вверх ссылается на хотя бы один член класса, который является текущим экземпляром или не зависимым его базовый класс. [Примечание: если такой элемент не найден, а текущий экземпляр имеет любые зависимые базовые классы, то Квалифицированный идентификатор является членом неизвестной специализации; Смотри ниже. -end note]
  • [...]

foo является текущим экземпляром. foo::iterator - это идентификатор с квалификацией, в котором спецификатор вложенных имен (foo::) относится к текущему экземпляру, а при поиске вверх "относится как минимум к одному члену класса, который является текущим экземпляром или не является -зависимый базовый класс"; поэтому он является членом текущего экземпляра. Поэтому [temp.res]/p3 не применяется, и не требуется typename. Вы по-прежнему можете добавить один или просто использовать iterator неквалифицированные напрямую.

Ответ 2

Из стандарта:

14.6.2.1 Зависимые типы [temp.dep.type]

1 Имя относится к текущему экземпляру, если оно

__ в определении шаблона класса, вложенного класса шаблона класса, члена шаблона класса или члена вложенного класса шаблона класса, имя введенного класса (раздел 9) шаблон класса или вложенный класс,

Имя foo относится к текущему экземпляру, что очевидно.

Так как iterator объявляется как вложенный класс в определении шаблона, iterator ссылается на имя в текущем экземпляре foo. foo::iterator совпадает с iterator.

using bar = foo::iterator;

а также

using bar = iterator;

должен работать.

Мне кажется, что вы столкнулись с дефектом MSVC.