c++ c++11 templates typetraits dependent-name

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



c++11 templates (3)

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

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

El type s en los rasgos std::remove_reference 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 usa typename std::remove_reference</*TYPE*/>::type ?


El type s en los rasgos std::remove_reference son tipos dependientes.

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

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

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

entonces debe usar typename para indicar que std::remove_reference<T>::type es un tipo ya que su expresión ahora depende del parámetro de plantilla T


En pocas palabras, necesita typename para asegurarse 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::type es un tipo. Pero, ¿qué pasa si alguien proporciona una especialización en la línea de

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

Ahora type no 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 que foo<T>::type realmente un tipo, no otra cosa, porque solo mirando la bar (y la plantilla primaria foo ) el compilador no puede saberlo.

Sin embargo, en su main el tipo std::remove_reference<int>::type no depende de un parámetro de plantilla, por lo tanto, el compilador puede verificar fácilmente si es un tipo.


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 descubrirlo por sí mismo, por lo que esta palabra clave no es necesaria.