Eu tenho o seguinte código:
template <typename TC>
class C
{
struct S
{
template <typename TS>
void fun() const
{}
};
void f(const S& s)
{
s.fun<int>();
}
};
// Dummy main function
int main()
{
return 0;
}
Ao compilar isso com o gcc 9.2 e o clang (9.0), estou recebendo um erro de compilação devido à template
exigência da palavra - chave para a chamada fun
. Clang mostra:
error: use 'template' keyword to treat 'fun' as a dependent template name
s.fun<int>();
^
template
Não entendo por que o compilador pensa que fun
é um nome dependente no contexto de f
, já que f
não é um modelo em si. Se eu mudar C
para ser uma classe regular em vez de um modelo, o erro desaparece; no entanto, não vejo por que deveria haver um erro em primeiro lugar, pois S
nem f
dependemos disso TC
.
Curiosamente, o MSVC 19.22 compila isso muito bem.
Nota
Antes de votar para fechar como idiota de Onde e por que tenho que colocar as palavras-chave "modelo" e "nome do tipo"? considere que este é um caso especial em que, mesmo que S
seja realmente um nome dependente, no contexto f
dele não seria dependente se não fosse pelo fato de serem membros da instanciação atual.
Respostas:
Considere :
s.a<0>(i)
é analisado como uma expressão que contém duas operações de comparação<
e>
, e isso é bom para o 1, mas falha para o 2.Se isso for alterado para
s.template a<0>(i)
, o item 2 está OK e o item 1 falha. Portanto, atemplate
palavra-chave nunca é redundante aqui.O MSVC é capaz de interpretar a expressão nos
s.a<0>(i)
dois sentidos no mesmo programa. Mas isso não está correto de acordo com o padrão; cada expressão deve ter apenas uma análise para o compilador lidar.fonte
C
ou outra, mas nunca pode instanciar as duas. Atemplate
palavra-chave aqui ainda é IMHO desnecessária, porque aS
escolha depende de qualC
instância você instancia. Sem atemplate
palavra-chave, você seria capaz de instanciar ambos, e o comportamento de f seria diferente para cada instância.<
seja um operador de comparação em uma instanciação de modelo e um colchete de ângulo de abertura em outra instanciação. Isso é para garantir que os compiladores possam analisar modelos em um AST (com espaços reservados para os tipos de modelo).fun
pode ou não ser uma função de modelo (ou pode não existir), dependendo do parâmetro de modelo declass C
.Isso porque você pode se especializar
S
(sem se especializarC
):Como o compilador deseja saber se
fun
é ou não um modelo quando olha pela primeira vezclass C
(antes de substituir o parâmetro do modelo),template
é necessário.fonte
S
podem ser acessadasf
. Se não puderem, ter essa restrição não faz sentido, porquef
não será capaz de vê-las de qualquer maneira.f
, encontra-o.