Почему ключевое слово typename не требуется в зависимых от шаблона именах вложенных типов в VS2015? - PullRequest
3 голосов
/ 25 сентября 2019

Я читал об использовании typename в шаблонном программировании на C ++ (например, это Q / A ).Мне кажется, что при использовании зависимого имени вложенного типа мы должны использовать typename, чтобы избежать разбора неоднозначности.Я также проверил это в книге Скотта Мейерса в действии C ++ , позиция № 42.

Но для меня странно то, что тот же пример в книге работает без typename.Вот код:

template<class C>
void Print2nd(const C & cont)
{
   if (cont.size() >= 2)
   {
      C::const_iterator * iter1 = new C::const_iterator(cont.begin());  // why typename is NOT needed?
      C::const_iterator   iter2 = cont.begin();                         // why typename is NOT needed?
      (*iter1)++;
      iter2++;
      int value1 = **iter1;
      int value2 = *iter2;

      std::cout << "The value of 2nd with pointer is: " << value1 << std::endl;
      std::cout << "The value of 2nd without pointer is: " << value2 << std::endl;
   }
}


int main()
{
   std::vector<int> vect = {1,2,3,4,5,6};
   Print2nd(vect);
   return 0;
}

Я использую VS2015.Итак, вопрос в том, почему typename не требуется в этом контексте?Есть ли какие-либо обновления в последних компиляторах C ++, чтобы избежать использования typename в таком контексте?Или я делаю ошибку в коде?

Обновление 1: Благодаря комментарию @ FrançoisAndrieux кажется, что то же самое происходит в VS2008 и VS2010, как сообщалось в это Q / A .

Ответы [ 2 ]

5 голосов
/ 25 сентября 2019

In typename там не нужно.В некоторых контекстах необходимость в typename была удалена, потому что синтаксически все, что там должно быть типом.

В частности:

Полное имя, котороепоявляется в идентификаторе типа, где наименьший включающий идентификатор типа:

  • тип в новом выражении, не заключающий в скобки его тип;

Цитируемый источник не является прямым стандартом, но довольно надежен.

До typename было необходимо там;это будет проанализировано как значение, и new value не является допустимым синтаксисом.В typename это необязательно в этом контексте.

Теперь не имеет особенности в нем;Вы видите, что MSVC не может правильно реализовать / / , а не расширение.

4 голосов
/ 25 сентября 2019

typename - это ;пример программы плохо сформирован.Если компилятор не диагностирует проблему, он не соответствует стандарту.Правильная версия:

typename C::const_iterator * iter1 = new typename C::const_iterator(cont.begin());
                                      // ^^^^^^^^ this one only required until C++20
typename C::const_iterator   iter2 = cont.begin();

Стандартная цитата (черновик для C ++ 17):

[temp.res]

Имя, используемое вобъявление шаблона или определение, и это зависит от atemplate-parameter, как предполагается, не называет тип, если применимый поиск имени не находит имя типа или имя квалифицируется ключевым словом typename.

C::const_iteratorзависит от шаблона-параметра C, поэтому его не следует считать именем типа, если не используется typename.Я думаю, что это утверждение следует интерпретировать как операцию умножения, но правый операнд является необъявленным идентификатором и поэтому неправильно сформирован.

C ++ 20 вводит правило, позволяющее удалить typename из выражения new(последний черновик):

[temp.res]

Говорят, что квалифицированное имя находится в контексте только с идентификатором типа, если оно появляется в идентификаторе типа, new-type-id , или определяющий-тип-идентификатор, а наименьший включающий идентификатор типа, новый-тип-идентификатор или определяющий-тип-идентификатор - это новый-тип-идентификатор, определяющий-тип-идентификатор, тип конечного возврата, аргумент по умолчанию для параметра типа шаблона или идентификатор типа для static_cast, const_cast, reinterpret_cast или dynamic_cast.


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

using const_iterator = typename C::const_iterator;

Или вы можете просто использовать auto:

auto it = cont.begin();

PS Вряд ли когда-либо имеет смысл динамически выделять итератор.

...