Por que não posso reduzir o ponteiro para os membros em argumentos de modelo?
-
26-09-2019 - |
Pergunta
Se eu fizer um membro ponteiro para base, posso convertê-lo em um membro ponteiro-derivado geralmente, mas não quando usado em um modelo como o zumbido abaixo, onde o primeiro argumento do modelo influencia o segundo. Estou lutando contra bugs do compilador ou o padrão realmente exige que isso não funcione?
struct Foo
{
int x;
};
struct Bar : public Foo
{
};
template<class T, int T::* z>
struct Buzz
{
};
static int Bar::* const workaround = &Foo::x;
int main()
{
// This works. Downcasting of pointer to members in general is fine.
int Bar::* y = &Foo::x;
// But this doesn't, at least in G++ 4.2 or Sun C++ 5.9. Why not?
// Error: could not convert template argument '&Foo::x' to 'int Bar::*'
Buzz<Bar, &Foo::x> test;
// Sun C++ 5.9 accepts this but G++ doesn't because '&' can't appear in
// a constant expression
Buzz<Bar, static_cast<int Bar::*>(&Foo::x)> test;
// Sun C++ 5.9 accepts this as well, but G++ complains "workaround cannot
// appear in a constant expression"
Buzz<Bar, workaround> test;
return 0;
}
Solução
Simplesmente não é permitido. De acordo com §14.3.2/5:
As conversões a seguir são realizadas em cada expressão usada como um argumento de modelo não do tipo. Se um argumento de modelo não do tipo não puder ser convertido para o tipo de parâmetro de modelo correspondente, o programa será mal formado.
-Para um parâmetro de modelo não do tipo de integral ou tipo de enumeração, são aplicadas promoções integrais (4.5) e conversões integrais (4.7).
-Para um parâmetro de modelo não do tipo de tipo de ponteiro de tipo para objeto, são aplicadas conversões de qualificação (4.4) e a conversão de matriz em ponte (4.2). -Para um parâmetro de modelo não do tipo de tipo de referência de tipo ao objeto, nenhuma conversa se aplica. O tipo referido pela referência pode ser mais qualificado pelo CV do que o tipo (de outra forma idêntico) do argumento do modelo. O parâmetro de modelo está ligado diretamente ao argumento do modelo, que deve ser um LValue.
-Para um parâmetro de modelo não do tipo de tipo de ponteiro de tipo para funcionar, apenas a conversão de função em ponte (4.3) é aplicada. Se o argumento do modelo representar um conjunto de funções sobrecarregadas (ou um ponteiro para esse), a função correspondente será selecionada no conjunto (13.4).
-Para um parâmetro de modelo não do tipo de referência de tipo à função, nenhuma conversões se aplica. Se o argumento do modelo representar um conjunto de funções sobrecarregadas, a função correspondente será selecionada no conjunto (13.4).
-Para um parâmetro de modelo não do tipo de ponteiro de tipo para a função do membro, nenhuma conversões se aplica. Se o argumento do modelo representar um conjunto de funções de membros sobrecarregadas, a função de membro correspondente será selecionada no conjunto (13.4).
— Para um parâmetro de modelo não do tipo de ponteiro de tipo para membro de dados, são aplicadas conversões de qualificação (4.4).
Eu enfatizei a conversão em relação ao ponteiro para os membros de dados. Observe que sua conversão (§4.11/2) não está listada. Em C ++ 0x, permanece o mesmo a esse respeito.