web-dev-qa-db-fra.com

Pourquoi n'est-il pas nécessaire d'utiliser le nom de type pour les types dépendants dans le cas suivant?

J'ai lu sur la suppression de la référence d'un type, ici .

Il donne l'exemple suivant:

#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 ?
}

Les types dans le std::remove_reference les traits sont des types dépendants.

Implémentation possible

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;};

Mais pourquoi n'utilise-t-il pas typename std::remove_reference</*TYPE*/>::type?

10
LernerCpp

Les types dans le std::remove_reference les traits sont des types dépendants.

Non, ils ne sont pas noms dépendants ici. Les arguments du modèle ont été spécifiés explicitement comme int, int& et int&&. Par conséquent, les types sont connus à ce stade.

En revanche, si vous utilisez std::remove_reference avec un paramètre de modèle, par exemple.

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

alors vous devez utiliser typename pour dire que std::remove_reference<T>::type est un type car votre expression dépend maintenant du paramètre de modèle T.

22
songyuanyao

En un mot, vous avez besoin de typename pour vous assurer que le compilateur

std::remove_reference<int>::type

est vraiment un type. Considérons un autre modèle

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

Ici foo::type est un type. Mais que se passe-t-il si quelqu'un propose une spécialisation

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

Maintenant, type n'est pas un type mais un int. Maintenant, lorsque vous utilisez foo dans un modèle:

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

Vous devez vous assurer que le compilateur foo<T>::type est vraiment un type, pas autre chose, car en ne regardant que bar (et le modèle primaire foo) le compilateur ne peut pas le savoir.

Cependant, dans votre main le std::remove_reference<int>::type ne dépend pas d'un paramètre de modèle, donc le compilateur peut facilement vérifier s'il s'agit d'un type.

5
idclev 463035818

Le mot-clé typename est utilisé pour aider le compilateur à analyser la source. Il indique que l'ID est un nom de type, pas un nom de variable ou un nom de méthode. Mais dans des situations comme ci-dessus, le compilateur peut le comprendre lui-même, donc ce mot-clé n'est pas requis.

0
Sergey Strukov