2012-06-09 7 views
11

Ich vermisse etwas Grundlegendes. Ich versuche, const-Array-Mitglieder zur Kompilierzeit zu verwenden.Compile-Time-Array-Konstanten

const int list[3] = { 2, 5, 7 }; 
const int a = list[2]; // this doesn't error? 

template<int N1, int N2> 
struct tmax { 
    enum { value = ((N1 > N2) ? N1 : N2) }; 
}; 

const int b = tmax<2,4>::value; 
const int c = tmax<list[0],list[1]>::value; // error is here 

int main() 
{ 
    return 0; 
} 

Fehler:

prog.cpp:10:24: error: 'list' cannot appear in a constant-expression 
prog.cpp:10:30: error: an array reference cannot appear in a constant-expression 

ist die relevent IDEOne link

Warum tut das nicht? Was vermisse ich? Was soll ich anders machen?

Antwort

9

Nur weil ein Objekt const ist, bedeutet das nicht, dass es sich um einen Ausdruck für die Kompilierzeitkonstante handelt.

main.cpp:10:20: error: non-type template argument is not a constant expression 
const int c = tmax<list[0],list[1]>::value; // error is here 
        ^~~~~~~ 
main.cpp:10:20: note: read of non-constexpr variable 'list' is not allowed in a constant expression 
main.cpp:1:11: note: declared here 
const int list[3] = { 2, 5, 7 }; 
     ^

Dies ist der Grund für constexpr:

constexpr int list[3] = { 2, 5, 7 }; 

template<int N1, int N2> 
struct tmax { 
    enum { value = ((N1 > N2) ? N1 : N2) }; 
}; 

const int b = tmax<2,4>::value; 
const int c = tmax<list[0],list[1]>::value; // works fine now 

Was, warum dies funktioniert:

const int a = list[2]; // this doesn't error? 

eine const Variable Initialisierung keinen konstanten Ausdruck erfordern:

int foo(int n) { 
    const int a = n; // initializing const var with a non-compile time constant 
+0

Ich hätte gedacht, dass constexpr hilfreich wäre, und jetzt, wo ich sehe, sehe ich, dass es eine breitere Akzeptanz hat, als ich dachte. Mit diesem gesagt, ein bisschen mehr eine Erklärung, warum die Deklaration von const int a funktioniert aber Liste [1] speziell nicht geschätzt wird. Vielen Dank. –

+0

OK, also Visual Studio 2012 plant nicht, constexpr zu unterstützen. Hat jemand andere Lösungen? Ich muss es nicht dafür verwenden, aber es wäre nett. –

+0

@ Std''OrgnlDave Ich habe mehr von der Compiler-Diagnose hinzugefügt, die genau erklärt, warum list [1] kein konstanter Ausdruck ist. – bames53

4

Ausdrücke sind keine Konstantenausdrücke, wenn sie einen oder mehrere unzulässige Unterausdrücke enthalten. Eine solche Klasse von unzulässiger Unterausdrücke ist:

  • eine L-Wert-zu-R-Wert-Umwandlung (4.1), es sei denn, es zu
    • einer glvalue von integralem oder Aufzählungstyp angewandt wird, die auf einen nicht verweist -volatile const Objekt mit einem vorhergehenden Initialisierung mit einem konstanten Ausdruck initialisiert oder
    • a glvalue von literalen Typ, der mit constexpr definiert auf ein nicht flüchtiges Objekt bezieht, oder das bezieht sich auf ein Subobjekt eines solchen Objekts oder
    • ein glvalue des literalen Typs, der sich auf ein nichtflüchtiges temporäres Objekt bezieht, dessen Lebensdauer nicht beendet ist, initialisiert mit einem konstanten Ausdruck;

Insbesondere während des Name eines const Objekts von ENUM oder intergral Typ initialisiert mit einem konstanten Initialisierer bildet einen konstanten Ausdruck (dessen Wert zu lesen ist, was die L-Wert-zu-R-Wert bewirkt, Konvertierung), Unterobjekte eines const Aggregatobjekts (wie list in Ihrem Beispiel, ein Array) nicht, würde aber, wenn constexpr deklariert werden.

const int list[3] = { 2, 5, 7 }; 
const int a = list[2]; 

Dies gilt aber a keinen konstanten Ausdruck darstellen, weil es nicht mit einem konstanten Ausdruck initialisiert wird.

Durch Ändern der Deklaration von list (wir müssen die Deklaration von a nicht ändern), können wir a einen konstanten Ausdruck bilden.

constexpr int list[3] = { 2, 5, 7 }; 
const int a = list[2]; 

Als list[2] ist nun ein konstanter Ausdruck , a ist nun ein const Objekt der intergral Typ mit einem konstanten Ausdruck initialisiert so kann a nun als konstanter Ausdruck verwendet werden.

+0

Es bringt mich fast zum Weinen, dass das Visual Studio 2k12 Constexpr nicht unterstützen wird. Ich habe Arrays wie diese in der Template-Metaprogrammierung noch nie benutzt, aber ich habe mich darauf gefreut ... –