¿Por qué no se requiere usar typename para tipos dependientes en el siguiente caso?


10

He estado leyendo sobre eliminar la referencia de un tipo, aquí .

Da el siguiente ejemplo:

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

Los types en los std::remove_referencerasgos son tipos dependientes.

Posible implementación

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

¿Pero por qué no se usa typename std::remove_reference</*TYPE*/>::type?

Respuestas:


22

Los types en los std::remove_referencerasgos son tipos dependientes.

No, no son nombres dependientes aquí. Los argumentos de la plantilla se han especificado explícitamente como int, int&y int&&. Por lo tanto, los tipos son conocidos en este punto.

Por otro lado, si lo usa std::remove_referencecon un parámetro de plantilla, p. Ej.

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

entonces tiene que usar typenamepara decir que std::remove_reference<T>::typees un tipo ya que su expresión ahora depende del parámetro de la plantilla T.


5

En pocas palabras, debe typenameasegurarse de que el compilador

std::remove_reference<int>::type

Realmente es un tipo. Consideremos alguna otra plantilla

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

Aquí foo::typehay un tipo. Pero, ¿qué pasa si alguien proporciona una especialización en la línea de

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

Ahora typeno es un tipo sino un int. Ahora cuando usas foo dentro de una plantilla:

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

Debe asegurarse de que el compilador sea foo<T>::typerealmente un tipo, no otra cosa, porque solo mirando bar(y la plantilla principal foo) el compilador no puede saberlo.

Sin embargo, en su mainel std::remove_reference<int>::typeparámetro no depende de la plantilla, por lo tanto, el compilador puede comprobar fácilmente si se trata de un tipo.


0

La palabra clave typename se usa para ayudar al compilador a analizar la fuente. Señala que la identificación es un nombre de tipo, no un nombre de variable o nombre de método. Pero en situaciones como el compilador anterior puede resolverlo por sí mismo, por lo que esta palabra clave no es necesaria.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.