Warum muss im folgenden Fall kein Typname für abhängige Typen verwendet werden?

10

Ich habe gelesen , über Bezug von einer Art zu entfernen, hier .

Es gibt das folgende Beispiel:

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

Die types in den std::remove_referenceMerkmalen sind abhängige Typen.

Mögliche Implementierung

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

Aber warum wird es nicht verwendet typename std::remove_reference</*TYPE*/>::type?

LernerCpp
quelle

Antworten:

22

Die types in den std::remove_referenceMerkmalen sind abhängige Typen.

Nein, sie sind hier keine abhängigen Namen . Die Vorlagenargumente wurden explizit als int, int&und angegeben int&&. Daher sind die Typen an dieser Stelle bekannt.

Wenn Sie dagegen std::remove_referenceeinen Vorlagenparameter verwenden, z

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

Dann müssen Sie typenamefeststellen, dass std::remove_reference<T>::typees sich um einen Typ handelt, da Ihr Ausdruck jetzt vom Vorlagenparameter abhängt T.

songyuanyao
quelle
5

Kurz gesagt, müssen Sie typenamesicherstellen, dass der Compiler dies tut

std::remove_reference<int>::type

ist wirklich ein Typ. Betrachten wir eine andere Vorlage

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

Hier foo::typeist ein Typ. Aber was ist, wenn jemand eine Spezialisierung nach dem Vorbild von liefert?

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

Jetzt typeist kein Typ sondern ein int. Wenn Sie jetzt foo in einer Vorlage verwenden:

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

Sie müssen sicherstellen, dass der Compiler foo<T>::typewirklich ein Typ ist, nicht etwas anderes, da der Compiler dies nur durch Betrachten bar(und der primären Vorlage foo) nicht wissen kann.

In Ihrem Fall hängt maindas std::remove_reference<int>::typejedoch nicht von einem Vorlagenparameter ab, sodass der Compiler leicht überprüfen kann, ob es sich um einen Typ handelt.

idclev 463035818
quelle
0

Das Schlüsselwort typename wird verwendet, um dem Compiler beim Parsen der Quelle zu helfen. Es zeigt an, dass die ID ein Typname ist, kein Variablenname oder Methodenname. In Situationen wie oben kann der Compiler dies jedoch selbst herausfinden, sodass dieses Schlüsselwort nicht erforderlich ist.

Sergey Strukov
quelle