2017-04-20 2 views
3
#include <iostream> 

using namespace std; 

template<const int arr[]> 
struct S { 
    static constexpr int value = arr[0]; 
}; 

constexpr int arr[] = { 5 }; 

int main() { 
    cout << S<arr>::value << endl; 
} 

Dieses Programm kompiliert feine und Drucke mit 5 gcc 5.1 und höher, aber MSVC 19.10.25019 gibt folgende Fehler:Verwendung constexpr Array als Templat nicht-Typargument (C++ 14)

Fehler C2975: ‚S‘: ungültige Template-Argument für ‚arr‘, erwartet Kompilierung-konstante Ausdruck Fehler C2131: Ausdruck hat nicht auf einen konstanten

Ist dieses Programm gültig beurteilen nach der C++ 14 Standard, oder gcc ist hier zu nachsichtig?

+0

Für der Datensatz akzeptiert auch Clang diesen Code. – jwimberley

+0

Was sagt MSVC, wenn Sie 'arr []' durch 'arr [1]' ersetzen? – jwimberley

+0

@jwimberley Es ändert nichts. –

Antwort

2

Das Programm ist so gut wie ich sehe.

Laut [temp.param]/8 hat der Vorlagenparameter tatsächlich den Typ const int*, nicht const int[].

A non-type template-Parameter vom Typ „Array von T“ oder „-Funktion zurückkehr T“ wird eingestellt, vom Typ „Zeiger auf T“ oder als „Zeiger T funktioniert Rückkehr“ bzw. .

Nach [temp.arg.nontype]/1, können wir den Namen eines vollständigen Array-Objekt mit statischen Speicherdauer und externe Bindung als Argument für eine solche Template-Parameter verwendet werden:

ein Template-Argument für einen nicht-Typ, nicht Vorlage Template-Parameter wird einer der folgenden sein:

...

- ein const ant-Ausdruck (5.19), der die Adresse eines vollständigen Objekts mit statischer Speicherdauer und externer oder interner Verknüpfung oder einer Funktion mit externer oder interner Verknüpfung bezeichnet, einschließlich Funktion Vorlagen und Funktion Vorlage-ID, jedoch nicht-statische Klassenmitglieder, ausgedrückt (ohne Berücksichtigung Klammern) als &ID-expression, wo die ID-expression der Name eines Objekts oder eine Funktion ist, mit der Ausnahme, dass die & wenn der Name auf eine Funktion oder ein Array verweist weggelassen werden, und wird weggelassen wenn der entsprechende Vorlage-Parameter eine Referenz ist ...

arr ist ein konstanter Ausdruck, trotz der Tatsache, dass MSVC denkt, dass es nicht ist. Es ist ein zentraler konstanter Ausdruck gemäß [expr.const]/2, da es keine verbotenen Auswertungen enthält und ein konstanter Ausdruck ist, da er auf ein Objekt mit statischer Speicherdauer ([expr.const]/4) zeigt.

Da der Vorlagenparameter auf ein Array mit statischer Speicherdauer verweist, sind die Grenzen des Arrays zum Zeitpunkt der Vorlageninstanziierung bekannt. Es kann daher verifizieren, dass der Zugriff auf arr[0] ein zulässiger Kernkonstantenausdruck ist, da er wohldefiniertes Verhalten aufweist und in die Kategorie der erlaubten lvalue-to-rvalue-Konvertierungen in [expr.const]/2:

... ein nichtflüchtiges glvalue von integralem oder Aufzählungstyp, der mit einer vorangehenden Initialisierung zu einem nichtflüchtigen const Objekt bezieht, mit einem konstanten Ausdruck initialisiert

+0

Technisch verletzt es [temp.arg.nontype] /2.1: "Für einen nicht-type template-Parameter des ... Zeigertyps darf der Wert des Konstantenausdrucks nicht ... die Adresse von ... a sein Unterobjekt ". Der Zeiger zeigt auf das erste Element des Arrays, das ein Unterobjekt ist. Aber das ist ein bekanntes Problem mit der aktuellen Formulierung; siehe CWG 2043. –

Verwandte Themen