Para usar um nome da classe base dependente no modelo de classe derivada (por exemplo, B<T>
), é preciso adicionar um prefixo destacando para o compilador que é um nome dependente ( B<T>::
). E para evitar fazer isso muitas vezes, uma declaração using pode ser usada em vez disso.
Abaixo o código com tal declaração de uso:
template <class T>
struct A {
constexpr static int x = 0;
};
template <class T>
struct B : A<T> {
// ok everywhere
constexpr static int y = B<T>::x;
// ok in MSVC
using B<T>::x;
constexpr static int z = x;
};
funciona bem no compilador MSVC, enquanto outros não gostam. Clang em particular reclama
erro: nenhum membro chamado 'x' em 'B'
Hovewer Clang não vê nenhum erro em y = B<T>::x
uma linha acima. Demonstração online: https://gcc.godbolt.org/z/PvKW753M8
Qual implementação está correta aqui e por quê?
O programa é IFNDR (mal formado, sem necessidade de diagnóstico).
Isso ocorre porque você nunca instancia nenhuma especialização, mas toda instanciação de uma especialização de
B
seria malformada. Veja [temp.res.general]/6.1 .Cada instanciação seria malformada porque
B<T>
nomeia a instanciação atual, ou seja, a classe atual, não uma classe base dela, mas o lado esquerdo do especificador de nome aninhado em umausing
declaração em um escopo de classe deve nomear uma base da classe atual (ou o nome inteiro deve nomear um enumerador). Veja [namespace.udecl]/3 .