5

Wenn ich ein Zeiger-zu-Basis-Mitglied mache, kann ich es normalerweise in ein Zeiger-zu-abgeleitetes-Element konvertieren, aber nicht innerhalb einer Vorlage wie Buzz unten, wo das erste Template-Argument das zweite beeinflusst. Bekämpfe ich Compilerfehler oder schreibt der Standard wirklich vor, dass dies nicht funktioniert?Warum kann ich Zeiger in Vorlagenargumenten nicht auf Mitglieder reduzieren?

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

Antwort

5

Es ist einfach nicht erlaubt. Nach §14.3.2/5:

Die folgenden Umwandlungen sind auf jedem Ausdruck durchgeführt als ein nicht-Typ template-Argument verwendet. Wenn ein nicht-types Template-Argument nicht in den Typ des entsprechenden Template-Parameters konvertiert werden kann, ist das Programm schlecht formatiert.
- Für einen nicht typisierten Template-Parameter vom Integral- oder Enumerationstyp werden Integral Promotions (4.5) und Integral Conversions (4.7) angewendet.
- Für einen nicht-type template-Parameter des Typs pointer to object werden Qualifizierungskonvertierungen (4.4) und die Array-to-Pointer-Konvertierung (4.2) angewendet. - Für einen nicht typisierten Vorlagenparameter vom Typ Verweis auf Objekt gelten keine Konvertierungen. Der Typ, auf den sich die Referenz bezieht, ist möglicherweise cv-qualifizierter als der (ansonsten identische) Typ des Template-Arguments. Der Template-Parameter ist direkt an das Template-Argument gebunden, das ein Lvalue sein muss.
- Für einen nicht-type Template-Parameter vom Typ Zeiger auf Funktion wird nur die Funktion-Zeiger-Konvertierung (4.3) angewendet. Wenn das Template-Argument eine Menge überladener Funktionen (oder einen Zeiger auf solche) darstellt, wird die Matching-Funktion aus der Menge (13.4) ausgewählt.
- Für einen nicht typisierten Vorlagenparameter vom Typ Verweis auf Funktion gelten keine Konvertierungen. Wenn das Template-Argument eine Menge überladener Funktionen darstellt, wird die Matching-Funktion aus der Menge (13.4) ausgewählt.
- Für einen nicht typisierten Vorlagenparameter vom Typ Zeiger zur Elementfunktion gelten keine Konvertierungen. Wenn das Template-Argument eine Menge überladener Memberfunktionen darstellt, wird die passende Memberfunktion aus der Menge (13.4) ausgewählt.
- Für einen nicht-type template-Parameter vom Typ pointer to data member werden Qualifizierungskonvertierungen (4.4) angewendet.

Ich habe die Konvertierung in Bezug auf Zeiger auf Datenmitglieder betont. Beachten Sie, dass Ihre Konvertierung (§4.11/2) nicht aufgelistet ist. In C++ 0x bleibt es in dieser Hinsicht gleich.

+0

Definitiv richtig, aber jede Idee, warum es nicht erlaubt ist? Scheint willkürlich. –

+1

@Joseph: Ich dachte es auch, weshalb ich auch C++ 0x überprüft habe. (Sie haben viele scheinbar willkürliche Entscheidungen entfernt, wie etwa keine Standardschablonenparameter für Funktionsschablonen.) Entweder hat niemand eine Verwendung dafür gefunden und so hat es sich nicht wirklich geändert/so wurde es einfach nicht gedrängt (es ist einfacher, einen Brunnen hinzuzufügen). Funktion getestet, als eine defekte Funktion abzulehnen), oder es gibt einen Grund, warum ich einfach nicht sehen kann. – GManNickG

Verwandte Themen