2010-10-26 33 views
5

Si je crée un pointeur vers un membre de base, je peux le convertir en un membre pointeur-dérivé, mais pas quand il est utilisé dans un modèle comme Buzz ci-dessous, où le premier argument influence le second. Est-ce que je me bats les bogues du compilateur ou est-ce que la norme exige vraiment que cela ne fonctionne pas?Pourquoi ne puis-je pas rediriger le pointeur vers des membres dans les arguments de modèle?

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; 
} 

Répondre

5

Ce n'est tout simplement pas autorisé. Conformément au §14.3.2/5:

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

J'ai souligné la conversion concernant le pointeur vers les membres de données. Notez que votre conversion (§4.11/2) n'est pas répertoriée. En C++ 0x, il reste le même à cet égard.

+0

Tout à fait raison, mais aucune idée pourquoi ce n'est pas autorisé? Cela semble arbitraire. –

+1

@Joseph: Je pensais que c'était aussi, c'est pourquoi j'ai aussi vérifié C++ 0x. (Ils ont supprimé de nombreuses décisions apparemment arbitraires, comme aucun paramètre de modèle par défaut pour les modèles de fonction.) Soit personne n'a trouvé d'utilisation pour cela et donc il n'a pas vraiment changé/donc il n'a simplement pas été poussé (il est plus facile d'ajouter un fonctionnalité testée que de déprécier une fonctionnalité cassée), ou il y a une raison fondamentale que je ne peux pas voir. – GManNickG