dłuższy komentarz jako wspólnotowe wiki.
Wyrażenie xs[0]
jest zdefiniowana w [expr.sub]/1 jako *((xs)+(0))
. (Patrz poniżej dla nawiasach.)
jedno z wyrażeń ma typu „wskaźnik do T
”, a drugi ma unscoped wyliczenie lub integralną typu.
Zatem macierz konwersji do wskaźnika [conv.array] stosuje się:
lwartością lub RValue typu „matrycy z N T
” lub „matrycy o nieznanym granica T
” Można zostać przekonwertowane na wartość typu "wskaźnik do T
". Wynikiem jest wskaźnik do pierwszego elementu tablicy.
Uwaga może działać na lwartością a wynik jest prvalue, 0
jako liczba całkowita dosłownym jest prvalue również. Dodawanie jest zdefiniowane w [expr.add]/5. Ponieważ oba są prvalues , nie jest wymagana żadna konwersja na wartość l do wartości r.
int arr[3];
constexpr int* p = arr; // allowed and compiles
Kluczowym krokiem wydaje się być pośredniość *
[expr.unary.op]/1
jednoargumentowych *
operator wykonuje pośredniość: określenie, do której jest stosowana, jako wskaźnik do typu obiektu lub wskaźnika do typu funkcji, a wynikiem jest lwartość odnosząca się do obiektu lub funkcji, której dotyczy wyrażenie.
więc wynikiem xs[0]
jest lwartością odnosząc się do pierwszego elementu tablicy xs
i jest typu int const
.
N.B. [expr.prim.general]/6
Wyrażenie parentetyzowane jest wyrażeniem pierwotnym, którego typ i wartość są identyczne z wyrażeniem zamkniętym. Obecność nawiasów nie wpływa na to, czy wyrażenie jest wartością l.
Jeśli teraz spojrzeć na kulami w [expr.const]/2, który uniemożliwi pewne wyrażenia i konwersje do stawienia się w stałych wyrażeń, jedyny pocisk, który mógłby ubiegać (AFAIK) jest lwartość-do -rvalue konwersja:
[...]
jednak tylko prawdziwy konwersji lwartość do RValue zgodnie (4,1) (nie 4.2, w którym jest tablica do wskaźnika), który pojawia się w ocenie xs[0]
jest konwersją z wynikowego l wartość odnosząca się do pierwszego elementu.
Dla przykładu w PO:
int const xs[]{1, 2, 3};
int as[xs[0]]; // error.
Element xs[0]
zawiera nielotny const integralną typu jego inicjalizacji poprzedza stałej ekspresji w których występuje, a została zainicjowana stałej ekspresji.
Nawiasem mówiąc, dodana „informacja” w cytowanym fragmencie [expr.const]/2 has been added to clarify że jest prawne:
constexpr char c = "hello"[0];
Należy zauważyć, że łańcuch jest dosłownym lwartością jako dobrze.
Byłoby wspaniale, gdyby ktoś (może zmienić to) wyjaśnić dlaczego xs[0]
nie może pojawić się w stałej ekspresji.
Wartości 'constexpr' mogą być obliczane w czasie kompilacji,' const' nie może. –
Tablica 'const' nie musi mieć widocznej definicji (może być" zewnętrzna "lub może być zdefiniowana później w pliku), dlatego istnieje różnica.Jeśli chodzi o powód, dla którego istnieje * ta * różnica, podejrzewam, że standard * mógł * powiedzieć, że gdy definicja jest obecna i jest odpowiednia dla 'constexpr' (jak w twoim kodzie), to' const' jest tak dobre jak 'constexpr', ponieważ w takim przypadku informacja jest dostępna do oceny. Nie wiem, dlaczego tak nie mówi, ale równie dobrym powodem jest "jeśli chcesz, żeby twoja tablica była" constexpr ", po prostu powiedz". –
Dodatek, który prawdopodobnie byłby dodatkiem do ciebie pytanie, wydaje mi się, dlaczego 'int const x = 5;' i 'constexpr int y = 5' może * oba * są używane jako wielkości stałe wielkości decybelów tablicy (' int a [x], b [y] '), ale wewnątrz tablic, które są traktowane inaczej (co odpowiada komentarzowi Steve'a powyżej). – WhozCraig