11

Ich denke, dass (gewisse) implizite Konvertierungen gelten, wenn nicht-type Template-Parameter übergeben werden. Zum Beispiel sollte es eine Umwandlung von int zu std::size_t für Ausdrücke wie std::array<int, 7> geben. Beachten Sie jedoch den folgenden Code:Wie die implizite Konvertierung für nicht typisierte Vorlagenparameter funktioniert?

template <bool> 
void f() { 
    std::cout << "false\n"; 
} 

template <> 
void f<true>() { 
    std::cout << "true\n"; 
} 

int main() { 
    f<1>(); 
    f<4>(); 
    f<0>(); 
} 

Ich erwarte, dass int implizit zu bool hier umgewandelt werden. Aber die Verhaltensweisen unterscheiden sich in VC, GCC und Clang.

Auf VC, true, false und false gedruckt werden, das ist wirklich komisch für mich.

Auf GCC, true, true und false gedruckt werden, was ich erwarte.

Während des Klingelns kompiliert der Code aufgrund der Anweisung f<4>(); überhaupt nicht.

Kandidatenvorlage ignoriert: für die 1. Template-Parameter

Also, was macht den Standard sagt über diese explizit angegebenes Argument ungültig? Was ist die implizite Konvertierungsregel für nicht typisierte Vorlagenparameter?

+0

Das VC-Verhalten ist zumindest klar: Es nimmt das LSB des Eingangsintegraltyps und verwendet diesen als booleschen Wert. Ich weiß immer noch nicht, welches Verhalten korrekt ist. –

+1

@MarkB Nicht wirklich, 'f <3>();' druckt immer noch 'false'. – Lingxi

Antwort

14

Aus dem Standard (§14.3.2/5):

Die folgenden Umwandlungen sind auf jedem Ausdruck durchgeführt, die als einen nicht-Typ template-Argument. Wenn ein Nicht-Typ Vorlage-Argument kann nicht in den Typ der entsprechenden Vorlage-Parameter konvertiert werden dann das Programm ist schlecht gebildet.

  • Für einen nicht-Typen template-Parameter von integralem oder Aufzählungstyp, in einem konvertierten konstanten Ausdruck erlaubten Umwandlungen (5,19) angelegt werden.

In §5.19 lernen wir (Hervorhebung von mir):

Ein integraler konstanter Ausdruck ist ein Ausdruck von integralen oder unscoped Aufzählungstyp, implizit zu einem prvalue umgewandelt, wo die Der umgewandelte Ausdruck ist ein zentraler konstanter Ausdruck. ... Ein konvertierter Konstantenausdruck von type T ist ein Ausdruck, der implizit in einen prvalue vom Typ T konvertiert wird, wobei der konvertierte Ausdruck ein zentraler Konstantenausdruck ist und die implizite Konvertierungssequenz nur benutzerdefinierte Konvertierungen, lvalue- to-rvalue Conversions (4.1), Integrated Promotions (4.5) und Integral Conversions (4.7) andere als die Konvertierungseinschränkungen (8.5.4). [Anmerkung: Solche Ausdrücke können in neuen Ausdrücken (5.3.4), als Fallausdrücke (6.4.2), als Enumeratorinitialisierer verwendet werden, wenn der zugrundeliegende Typ fest ist (7.2), als Arraygrenzen (8.3.4), und als Integral oder Aufzählung nicht-type Vorlage Argumente (14.3). -Ende note]

So Umwandlungen Verengung (wie 4-bool Umwandlung) für integrale Konstante Ausdrücke explizit nicht erlaubt, die in diesem Fall als nicht-Typ Template-Argument erforderlich sind. Das macht den Anruf f<4>() schlecht gemacht.

Ich glaube, Clang ist korrekt in der Ausgabe eines Fehlers, und GCC und VC sind beide nicht konform für keine Diagnose.

[Update] Dies ist GCC Bug #57891, sieht aus wie es derzeit nicht zugewiesen ist.

+0

Können Sie einen Verweis auf den Standard über die Umwandlung von "0" und "1" nach "bool" geben, ohne sich zu verengen? – Lingxi

+0

OK, ich finde es anscheinend selbst. _Eine einschränkende Konvertierung ist eine implizite Konvertierung von einem Aufzählungstyp vom Typ Integer oder nicht aufgeschnitten in einen Integer-Typ, der nicht alle Werte des ursprünglichen Typs darstellen kann, außer wenn die Quelle ein konstanter Ausdruck ist und der tatsächliche Wert nach der Konvertierung in den Zieltyp passt und wird den ursprünglichen Wert erzeugen, wenn zurück in den ursprünglichen Typ konvertiert wird. – Lingxi

+0

Ich habe einen Fehler für VC++ [hier] (https://connect.microsoft.com/VisualStudio/feedback/details/2283106) eingereicht. – ildjarn

Verwandte Themen