Dlaczego nie jest wymagane używanie nazwy typu dla typów zależnych w następującym przypadku?

10

Czytałem o usuwaniu odwołania do typu tutaj .

Daje następujący przykład:

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

W typesw std::remove_referencecechami są rodzaje zależnych.

Możliwe wdrożenie

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

Ale dlaczego nie używa typename std::remove_reference</*TYPE*/>::type?

LernerCpp
źródło

Odpowiedzi:

22

W typesw std::remove_referencecechami są rodzaje zależnych.

Nie, nie są to tutaj nazwy zależne . Argumenty szablonu zostały wyraźnie określone jako int, int&i int&&. Dlatego typy są znane w tym momencie.

Z drugiej strony, jeśli używasz std::remove_referencez parametrem szablonu, np

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

musisz użyć, typenameaby powiedzieć, że std::remove_reference<T>::typejest to typ, ponieważ twoje wyrażenie zależy teraz od parametru szablonu T.

songyuanyao
źródło
5

W skrócie, musisz typenameupewnić się, że kompilator to

std::remove_reference<int>::type

naprawdę jest typem. Rozważmy inny szablon

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

Oto foo::typetyp. Ale co, jeśli ktoś zapewni specjalizację zgodnie z

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

Teraz typenie jest typem, ale int. Teraz, gdy używasz foo wewnątrz szablonu:

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

Musisz upewnić się, że kompilator foo<T>::typejest naprawdę typem, a nie czymś innym, ponieważ tylko patrząc na bar(i podstawowy szablon foo) kompilator nie może tego wiedzieć.

Jednak w maintym std::remove_reference<int>::typenie zależy od parametru szablonu, stąd kompilator może łatwo sprawdzić, czy jest to typ.

idclev 463035818
źródło
0

Słowo kluczowe typename służy kompilatorowi do analizy źródła. Wskazuje, że id jest nazwą typu, a nie nazwą zmiennej lub nazwą metody. Ale w sytuacjach takich jak powyższy kompilator może sam to zrozumieć, więc to słowo kluczowe nie jest wymagane.

Siergiej Strukow
źródło