2014-05-01 12 views
17

Czy fragment koduCzy członkowie tablicy constexpr kompilują stałe czasowe?

struct Parameters { 
    static constexpr int n = 2; 
    static constexpr double v[n] = {4.0, 5.0}; 
}; 

prawny C++ 11? A jeśli tak, to czy są to stałe czasowe kompilujące lub czy jest to tylko wskaźnik Parameters::v (cokolwiek oznaczałoby to w czasie kompilacji)?

Jak widać, jestem ogólnie nieco zmieszany z tablicami constexpr i ich inicjowaniem w klasach/strukturach. Proszę nie tylko odpowiedzieć na moje konkretne pytanie, ale także wspomnieć o typowych pułapkach i tym podobnych dotyczących tego tematu.

+5

Należy zauważyć, że 'v' nie jest wskaźnikiem, to tablica. – Angew

+0

Wydaje się być całkowicie legalnym: http://ideone.com/oMwXAj –

+0

możliwy duplikat [\ 'x \ [0 \] == 1 \' wyrażenie stałe w C++ 11, gdy x jest const int \ [\] ?] (http://stackoverflow.com/questions/18903113/x0-1-constant-expression-in-c11-when-x-is-const-int) –

Odpowiedz

4

Nie widzę problemu z konstrukcją. Cytowanie C++ 11, [dcl.constexpr]:

§1 constexpr specifier stosuje się jedynie do definicji zmiennej, deklaracja funkcji lub funkcji szablonu lub deklaracji statycznego członka danych na poziomie rodzaj literowy (3.9). ...

§9 Specyfikator A constexpr używany w deklaracji obiektu deklaruje obiekt jako const. Taki obiekt będzie miał literał i będzie inicjowany. Jeśli zostanie zainicjowane przez wywołanie konstruktora, to wywołanie będzie stałym wyrażeniem (5.19). W przeciwnym razie lub jeśli w deklaracji referencyjnej zostanie użyty specyfikator constexpr, każde wyrażenie pełnotekstowe pojawiające się w jego inicjatorze będzie stałym wyrażeniem. Każda niejawna konwersja użyta w konwersji konwertująca wyrażenia inicjalizacyjne i każde wywołanie konstruktora użyte do inicjalizacji musi być jedną z tych dozwolonych w wyrażeniu stałym (5.19).

double jest typem dosłownym, podobnie jak tablica typów literalnych. Co oznacza, że ​​v[0] i v[1] z twojego kodu są rzeczywiście wyrażeniami stałymi.

1
struct Parameters { 
    static constexpr int n = 2; 
    static constexpr double v[n] = {4.0, 5.0}; 
}; 

int main() { 
    constexpr int a = Parameters::v[0]; 
    return 0; 
} 

Ten kod na gcc 4.8.2 kompiluje się, co następuje:

0000000000000000 <main>: 
    0: 55      push rbp 
    1: 48 89 e5    mov rbp,rsp 
    4: c7 45 fc 04 00 00 00 mov DWORD PTR [rbp-0x4],0x4 
    b: b8 00 00 00 00   mov eax,0x0 
    10: 5d      pop rbp 
    11: c3      ret 

Więc tak, jest to kompilacja stała czasowa.

dzyń 3,4 produkuje podobny kod:

0000000000000000 <main>: 
    0: 55      push rbp 
    1: 48 89 e5    mov rbp,rsp 
    4: b8 00 00 00 00   mov eax,0x0 
    9: c7 45 fc 00 00 00 00 mov DWORD PTR [rbp-0x4],0x0 
    10: c7 45 f8 04 00 00 00 mov DWORD PTR [rbp-0x8],0x4 
    17: 5d      pop rbp 
    18: c3      ret 

Ponownie, jest to kompilacja stała czasowa.

Wszystko zostało skompilowane z opcją -O0.

P.S .: Jeśli a jest const, to dla gcc nic się nie zmienia, ale dla clang ma wartość 4 nie jest wywoływana bezpośrednio tak, jakby była stałą czasu kompilacji.

Jeśli a nie jest zadeklarowane jako const lub constexpr, to oba kompilatory nie traktują Parametrów :: v [0] jako stałej czasowej kompilacji.

2
struct Parameters { 
    static constexpr int n = 2; 
    static constexpr double v[n] = {4.0, 5.0}; 
}; 

Ten fragment sam w sobie jest z pewnością legalny, o ile wiem. Sekcja 7.1.5 [dcl.constexpr] standardu C++ 11 mówi, że

constexpr specifier stosuje się tylko do ... deklaracji statycznego członka danych dosłownym typu

i typu dosłowny jest zdefiniowana w 3.9:

typ to typ dosłownym jeśli jest to:

- rodzaj skalarny; lub ...

- tablica dosłownym typu

Więc static constexpr double v[2] = { ... } jest z pewnością ważne ile mogę powiedzieć.

Co do tego, czy członkowie tablicy są constexpr ... nie jestem pewien. Jeśli deklarujemy

constexpr double d = Parameter::v[1]; 

następnie obie g ++ i brzęk skompilować je w porządku, ale wersja dzyń nie odwołuje się z nieokreślonej odniesieniu do Parameters::v. Nie wiem, czy to wskazuje na błąd Clang, czy też konstrukcja jest nieważna.

+0

Technicznie, nie sądzę, że członkowie tablicy mogą być 'constexpr', ponieważ nie są kompletnymi obiektami. Ale i tak nie możesz uzyskać do nich dostępu bezpośrednio, możesz uzyskać do nich dostęp tylko przez wyrażenie 'Parametry :: v [0]' (lub '1'). A to zaspakaja wszystkie wymagania ciągłej ekspresji. – Angew

+0

@Angew Ale z praktycznego punktu widzenia adres 'Parametrów :: v' zostanie ustawiony przez linker lub środowisko wykonawcze i nie będzie znany kompilatorowi. Tak naiwnie, '* (Parametry :: v + 1)' jako 'constexpr' byłoby nieco trudne? –

+1

'C++ 11 [wyrażenie.konst.] §2,3' definiuje wymagania dotyczące stałych wyrażeń, a dereferencja macierzy nie narusza żadnego z nich. To ciągły wyraz. – Angew