2012-06-09 14 views
11

Wydaje mi się, że brakuje mi czegoś podstawowego. Próbuję użyć członków tablicy const podczas kompilacji.Stałe szeregowe w czasie kompilacji

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

Błędy:

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 

Oto relevent IDEOne link

Więc dlaczego nie ta praca? czego mi brakuje? Co powinienem zrobić inaczej?

Odpowiedz

9

Tylko dlatego, że obiekt jest const, nie oznacza, że ​​jest to wyrażenie czasu kompilacji.

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

To jest powód, dla 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 

Jak, dlaczego to działa:

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

inicjalizacji zmiennej const nie wymaga stałej ekspresji:

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

Pomyślałem, że constexpr będzie pomocny, a teraz, gdy patrzę, widzę, że ma szersze zastosowanie, niż myślałem. W związku z tym, nieco więcej wyjaśnienia, dlaczego deklaracja const int a works, ale lista [1] w szczególności nie byłoby docenione. Dziękuję Ci. –

+0

OK, więc visual studio 2012 nie planuje obsługiwać constexpr. Czy ktoś ma jakieś inne rozwiązania? NIE MAM tego używać, ale byłoby miło. –

+0

@ std''OrgnlDave Dodałem więcej diagnostyki kompilatora, która wyjaśnia, dlaczego lista [1] nie jest wyrażeniem stałym. – bames53

4

Wyrażenia nie są wyrażeń stałych, jeśli zawierają jedną z wielu niedozwolonych podwyrażeń. Jedną z klas niedozwolonych pod wyrażeń jest:

  • lwartością do RValue konwersji (4.1), o ile jest on stosowany do
    • w glvalue integralnego lub wyliczania typu, który odnosi się do niearomatycznego -wolny obiekt const z poprzednią inicjalizacją , zainicjalizowany stałą ekspresją lub glownością typu literalnego, która odnosi się do nieulotnego obiektu zdefiniowanego przez constexpr, lub który odnosi się do pod-obiektu takiego obiektu lub
    • glwartość typu literalnego, która odnosi się do nieulotnego obiektu tymczasowego, którego żywotność nie została zakończona, zainicjalizowana za pomocą stałego wyrażenia;

W szczególności, podczas gdy nazwa const przedmiotu wyliczenia lub Zintegrowanego typu inicjowane przy stałym inicjator stanowi stałej ekspresji (odczytaniem wartości, co powoduje lwartość-to-RValue konwersja), sub-obiekty obiektu zagregowanego const (takie jak list w twoim przykładzie, tablica) nie, ale będą, jeśli zostaną zadeklarowane constexpr.

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

Jest to ważne, ale a nie stanowi stałą ekspresję ponieważ nie jest inicjowany z stałej ekspresji.

Zmieniając deklarację list (nie musimy zmieniać deklaracji a), możemy uczynić a formą stałego wyrażenia.

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

jako list[2] jest teraz stałej ekspresji, a jest teraz const Przedmiotem Zintegrowanego typu inicjowane z stałej ekspresji tak a może być obecnie używany jako stały ekspresji.

+0

To prawie sprawia, że ​​płaczę, że studio graficzne 2k12 nie będzie obsługiwać constexpr. Nigdy nie używałam takich tablic w metaprogramowaniu szablonów, ale nie mogłam się doczekać ... –