Pourquoi ne puis-je pas descendre le pointeur sur les membres dans les arguments de modèle?

Si je crée un pointeur vers un membre base, je peux le convertir en un pointeur vers un membre dérivé, mais pas lorsqu’il est utilisé dans un modèle comme Buzz ci-dessous, où le premier argument du modèle influence le second. Suis-je en train de lutter contre les bogues du compilateur ou la norme impose-t-elle vraiment que cela ne fonctionne pas?

struct Foo { int x; }; struct Bar : public Foo { }; template 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 test; // Sun C++ 5.9 accepts this but G++ doesn't because '&' can't appear in // a constant expression Buzz<Bar, static_cast(&Foo::x)> test; // Sun C++ 5.9 accepts this as well, but G++ complains "workaround cannot // appear in a constant expression" Buzz test; return 0; } 

Ce n’est tout simplement pas autorisé. Selon § 14.3.2 / 5:

Les conversions suivantes sont effectuées sur chaque expression utilisée comme argument de modèle non typé. Si un argument de modèle non-type ne peut pas être converti en type du paramètre de modèle correspondant, le programme est mal formé.
– pour un modèle-paramètre de type intégral ou de type énumération non-type, les promotions intégrales (4.5) et les conversions intégrales (4.7) sont appliquées.
– pour un paramètre de modèle non typé de type pointeur sur object, les conversions de qualification (4.4) et la conversion de pointeur à pointeur (4.2) sont appliquées. – Pour un paramètre modèle non-type de type référence à object, aucune conversion ne s’applique. Le type référencé par la référence peut être plus qualifié cv que le type (sinon identique) de l’argument de modèle. Le paramètre template est directement lié à l’argument template, qui doit être une valeur.
– Pour un paramètre template non-type de type pointeur à fonction, seule la conversion fonction à pointeur (4.3) est appliquée. Si l’argument modèle représente un ensemble de fonctions surchargées (ou un pointeur sur un tel), la fonction correspondante est sélectionnée dans l’ensemble (13.4).
– Pour un paramètre modèle non-type de type référence à fonction, aucune conversion ne s’applique. Si l’argument modèle représente un ensemble de fonctions surchargées, la fonction correspondante est sélectionnée dans l’ensemble (13.4).
– Pour un paramètre-modèle non typé de type pointeur vers une fonction membre, aucune conversion ne s’applique. Si l’argument modèle représente un ensemble de fonctions de membre surchargées, la fonction de membre correspondante est sélectionnée dans l’ensemble (13.4).
Pour un paramètre de modèle non typé de type pointeur sur un membre de données, les conversions de qualification (4.4) sont appliquées.

J’ai mis l’accent sur la conversion concernant le pointeur sur les membres de données. Notez que votre conversion (§4.11 / 2) ne figure pas dans la liste. En C ++ 0x, il rest le même à cet égard.