Descargo de responsabilidad
esta no es una respuesta, sino un comentario largo
Mis habilidades de abogado de idiomas son demasiado bajas para entender completamente el estándar, pero aquí hay algunas cosas que descubrí al experimentar con el código. Todo lo que sigue se basa en mi comprensión (lejos de ser perfecta) del asunto y probablemente necesite algunas revisiones.
Investigación
En primer lugar, fui a una versión estándar completamente definida (C ++ 17), por lo que operamos en una implementación bien definida.
Al mirar este código , parece que MSVC todavía tiene algunos problemas (¿con su búsqueda, supongo?) Cuando se trata de creación de instancias y redefinición de plantillas. No confiaría tanto en MSVC en nuestro escenario.
Dicho esto, pensemos por qué podríamos necesitar la templatepalabra clave en
return yF.template head<1>();
Nombres dependientes
A veces, dentro de las plantillas, tenemos que ayudar al compilador a decidir si un nombre se refiere a
- un valor
int T::x = 0,
- un tipo
struct T::x {};o
- una plantilla
template <typename U> T::foo<U>();
Si nos referimos a un valor, no hacemos nada. Si nos referimos a un tipo, tenemos que usar typename. Y si nos referimos a una plantilla que usamos template. Más sobre ese tema se puede encontrar aquí .
No entiendo la especificación estándar cuando se trata de la definición real de un nombre dependiente, pero aquí hay algunas observaciones.
Observaciones
Veamos el código de referencia.
template <int N>
struct Matrix
{
template <int Idx>
int head() { return Idx; }
};
template <typename T>
struct Test
{
static constexpr int RayDim = 3;
int func() const
{
Matrix<RayDim> yF;
return yF.head<1>(); // clang complains, gcc and msvc are ok
}
};
struct Empty {};
int test()
{
Test<Empty> t;
return t.func();
}
Por RayDimlo general, debe ser un nombre dependiente (porque está dentro de la plantilla Test), lo que también podría Matrix<RayDim>ser un nombre dependiente. Por ahora, supongamos que en Matrix<RayDim>realidad es un nombre dependiente. Esto también hace Matrix<RayDim>::headun nombre dependiente. Como Matrix<RayDim>::heades una función con plantilla, es una plantilla en sí misma y se aplican las reglas de los nombres dependientes de arriba, lo que requiere que usemos la templatepalabra clave. Esto es de lo que se queja el ruido metálico.
Sin embargo, dado que RayDimse define dentro Testy functambién se define dentro de la misma plantilla y no una función con plantilla en sí misma, no creo que en RayDimrealidad sea un nombre dependiente en el contexto de func. Además, RayDimno se basa en los argumentos de plantilla de Test. En este caso, Matrix<RayDim>y Matrix<RayDim>::headrespectivamente, se convertirían en nombres no dependientes, lo que nos permite omitir la templatepalabra clave. Es por eso que compila gcc (y msvc).
Si tuviéramos RayDimtambién una plantilla , como aquí
template <typename>
static constexpr int RayDim = 3;
gcc también lo trataría como un nombre dependiente (lo cual es correcto, ya que puede haber una especialización de plantilla más adelante, por lo que no lo sabemos en ese momento). Mientras tanto, msvc acepta felizmente todo lo que le arrojamos.
Conclusión
Parece que se reduce a si RayDimes un nombre dependiente en el contexto de Test<T>::funco no. Clang cree que sí, gcc no. De alguna prueba más, parece que msvc está del lado del sonido metálico en este caso. Pero también está haciendo algo propio, así que ¿quién sabe?
Me pondría del lado de gcc aquí ya que no veo ninguna forma posible de RayDimvolverse dependiente en el punto donde funcse instancia.