Почему не обязательно использовать typename для зависимых типов в следующем случае?

10

Я читал об удалении ссылки типа здесь .

Это дает следующий пример:

#include <iostream> // std::cout
#include <type_traits> // std::is_same

template<class T1, class T2>
void print_is_same() {
  std::cout << std::is_same<T1, T2>() << '\n';
}

int main() {
  std::cout << std::boolalpha;

  print_is_same<int, int>();
  print_is_same<int, int &>();
  print_is_same<int, int &&>();

  print_is_same<int, std::remove_reference<int>::type>(); // Why not typename std::remove_reference<int>::type ?
  print_is_same<int, std::remove_reference<int &>::type>();// Why not typename std::remove_reference<int &>::type ?
  print_is_same<int, std::remove_reference<int &&>::type>();// Why not typename std::remove_reference<int &&>::type ?
}

В typeы в std::remove_referenceчертах зависимые типы.

Возможная реализация

template< class T > struct remove_reference      {typedef T type;};
template< class T > struct remove_reference<T&>  {typedef T type;};
template< class T > struct remove_reference<T&&> {typedef T type;};

Но почему он не использует typename std::remove_reference</*TYPE*/>::type?

LernerCpp
источник

Ответы:

22

В typeы в std::remove_referenceчертах зависимые типы.

Нет, они не являются зависимыми именами здесь. Аргументы шаблона были указаны явно как int, int&и int&&. Следовательно, типы известны на данный момент.

С другой стороны, если вы используете std::remove_referenceс параметром шаблона, например,

template <typename T>
void foo() {
    print_is_same<int, typename std::remove_reference<T>::type>();
}

тогда вы должны использовать, typenameчтобы сказать, что std::remove_reference<T>::typeэто тип, поскольку ваше выражение теперь зависит от параметра шаблона T.

songyuanyao
источник
5

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

std::remove_reference<int>::type

на самом деле это тип. Давайте рассмотрим другой шаблон

template <typename T>
struct foo {
    using type = int;
};

Вот foo::typeтип. Но что, если кто-то предоставит специализацию по линии

template <> struct foo<int> {
    int type;
};

Теперь typeэто не тип, а int. Теперь, когда вы используете foo внутри шаблона:

template <typanem T> 
struct bar {
    using type = typename foo<T>::type;
};

Вы должны убедиться, что компилятор foo<T>::typeдействительно является типом, а не чем-то другим, потому что только глядя на bar(и основной шаблон foo) компилятор не может этого знать.

Тем не менее, ваш mainпараметр std::remove_reference<int>::typeне зависит от параметра шаблона, поэтому компилятор может легко проверить, является ли он типом.

idclev 463035818
источник
0

Ключевое слово typename используется, чтобы помочь компилятору разобрать источник. Он указывает, что идентификатор является именем типа, а не именем переменной или метода. Но в ситуациях, подобных описанным выше, компилятор может выяснить это сам, поэтому это ключевое слово не требуется.

Сергей Струков
источник