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 rasgosstd::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.