aviso Legal
isso não é uma resposta, mas um longo comentário
Minhas habilidades com advogados de idiomas são muito baixas para entender completamente o padrão, mas aqui estão algumas coisas que descobri ao experimentar o código. Tudo o que se segue é baseado no meu entendimento (longe de ser perfeito) do assunto e provavelmente precisa de algumas revisões.
Investigação
Primeiro, fui para uma versão padrão totalmente definida (C ++ 17), para que operemos em uma implementação bem definida.
Olhando para este código , parece que o MSVC ainda tem alguns problemas (com sua pesquisa, eu acho?) Quando se trata de instanciação e redefinição de modelo. Eu não confiaria muito na MSVC em nosso cenário.
Dito isto, vamos pensar por que precisamos da templatepalavra-chave em
return yF.template head<1>();
Nomes dependentes
Às vezes, dentro dos modelos, precisamos ajudar o compilador a decidir se um nome se refere a
- um valor
int T::x = 0,
- um tipo
struct T::x {};ou
- Uma amostra
template <typename U> T::foo<U>();
Se nos referimos a um valor, não fazemos nada. Se nos referimos a um tipo, temos que usar typename. E se nos referirmos a um modelo que usamos template. Mais sobre esse assunto pode ser encontrado aqui .
Não entendo a especificação padrão quando se trata da definição real de um nome dependente, mas aqui estão algumas observações.
Observações
Vamos dar uma olhada no código de referência
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();
}
Geralmente RayDimdeve ser um nome dependente (porque está dentro do modelo Test), o que causaria Matrix<RayDim>também um nome dependente. Por enquanto, vamos supor que Matrix<RayDim>realmente seja um nome dependente. Isso cria Matrix<RayDim>::headum nome dependente também. Como Matrix<RayDim>::headé uma função de modelo, é um modelo em si e as regras dos nomes dependentes acima se aplicam, exigindo o uso da templatepalavra - chave. É disso que o clang está reclamando.
No entanto, como ele RayDimé definido por dentro Teste functambém é definido dentro do mesmo modelo e não por uma função de modelo em si, não acho RayDimque seja um nome dependente no contexto de func. Além disso, RayDimnão depende dos argumentos do modelo de Test. Nesse caso, Matrix<RayDim>e Matrix<RayDim>::headrespectivamente, se tornariam nomes não dependentes, o que nos permite omitir a templatepalavra - chave. É por isso que o gcc (e o msvc) são compilados.
Se fôssemos RayDimmodelar também, como aqui
template <typename>
static constexpr int RayDim = 3;
O gcc também o trataria como um nome dependente (o que é correto, pois pode haver uma especialização de modelo posteriormente, para que não saibamos nesse momento). Enquanto isso, o msvc aceita com satisfação tudo o que jogamos nele.
Conclusão
Parece que está se resumindo a RayDimum nome dependente no contexto Test<T>::funcou não. Clang pensa que é, gcc não. A partir de mais alguns testes, parece que os lados do msvc tocam nesse. Mas também é meio que fazer coisas próprias, então quem sabe?
Eu ficaria do lado do gcc aqui, pois não vejo uma maneira possível de me RayDimtornar dependente no ponto em que funcé instanciado.