2014-05-01 6 views
17

Ist das CodefragmentSind constexpr Array-Mitglieder Zeitkonstanten kompilieren?

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

Rechts 11 C++? Und wenn ja, sind Parameters::v[0] und Parameters::v[1] Kompilierzeitkonstanten oder ist nur der Zeiger Parameters::v selbst ein constexpr (was auch immer das zur Kompilierzeit bedeuten würde)?

Wie Sie sehen können, bin ich allgemein ein wenig verwirrt über constexpr Arrays und ihre Initialisierung in Klassen/Strukturen. Bitte zögern Sie nicht nur meine spezifische Frage zu beantworten, sondern auch allgemeine Fallstricke und ähnliches zu diesem Thema zu erwähnen.

+5

Beachten Sie, dass 'v' kein Zeiger ist, es ist ein Array. – Angew

+0

Scheint vollkommen legal zu sein: http://ideone.com/oMwXAj –

+0

möglich duplicate von [\ 'x \ [0 \] == 1 \' konstanter Ausdruck in C++ 11 wenn x const int \ [\] ?] (http://stackoverflow.com/questions/18903113/x0-1-constant-expression-in-c11-when-x-is-const-int) –

Antwort

4

Ich sehe kein Problem mit dem Konstrukt. Zitiert C++ 11, [dcl.constexpr]:

§1 Der constexpr Spezifizierer gilt nur für die Definition einer Variablen, die Erklärung einer Funktion oder Funktionsschablone oder die Deklaration eines statischen Datenelementes einer aufgebracht werden Literaltyp (3.9). ...

§9 Ein in einer Objektdeklaration verwendeter Spezifizierer constexpr deklariert das Objekt als const. Solch ein Objekt muss den literalen Typ haben und initialisiert werden. Wenn es durch einen Konstruktoraufruf initialisiert wird, sollte dieser Aufruf eine konstante Formel sein (5.19). Andernfalls, oder wenn in einer Referenzdeklaration ein consExpr-Spezifizierer verwendet wird, muss jeder Vollausdruck , der in seinem Initialisierer erscheint, ein konstanter Ausdruck sein. Jede implizite Umwandlung, die in verwendet wird, um die Initialisiererausdrücke und jeden Konstruktoraufruf, der für die Initialisierung verwendet wird, zu konvertieren, muss einer der in einem konstanten Ausdruck (5.19) zulässigen sein.

double ist ein Literaltyp und ein Array von Literaltypen. Das bedeutet, dass v[0] und v[1] aus Ihrem Code tatsächlich konstante Ausdrücke sind.

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

Dieser Code auf gcc kompiliert 4.8.2 in die folgenden:

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 

Also ja, es ist eine Kompilierung konstant ist.

Klirren 3.4 erzeugt einen ähnlichen Code:

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 

Wieder ist es eine Kompilierung konstant ist.

Alles wurde mit -O0 kompiliert.

S.S .: Wenn a als const deklariert ist, dann ändert sich für gcc nichts, aber für clang wird der Wert 4 nicht direkt verschoben, als wäre es eine Kompilierzeitkonstante.

Wenn a weder const noch constexpr deklariert ist, können beide Compiler Parameter :: v [0] nicht als Kompilierzeitkonstante behandeln.

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

Dieses Fragment an sich ist sicherlich legal, soweit ich das beurteilen kann. Abschnitt 7.1.5 [dcl.constexpr] des C++ 11-Standard, so dass

Der constexpr Spezifizierer wird nur angewendet werden auf ... der Deklaration eines statischen Datenelement einer Literal-Typ

und eine Literal-Typ wird in 3.9 definiert:

A-Typ ein Literal-Typ ist, wenn er:

- einen skalaren Typ; oder ...

- ein Array von wörtlichen Typ

So static constexpr double v[2] = { ... } ist sicherlich gültig, soweit ich das beurteilen kann.

Ob die Mitglieder des Arrays sind constexpr ... Ich bin mir nicht sicher. Wenn wir beide

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

dann g ++ und Klirren kompiliert es in Ordnung, erklären, aber die Klirren Version schlägt mit einem undefinierten Bezug auf Parameters::v zu verknüpfen. Ich weiß nicht, ob das auf einen Clang-Bug hinweist oder ob das Konstrukt ungültig ist.

+0

Technisch glaube ich nicht, dass die Mitglieder des Arrays "constexpr" sein können, da sie keine vollständigen Objcets sind. Sie können jedoch nicht direkt auf sie zugreifen, Sie können sie nur über den Ausdruck 'Parameters :: v [0]' (oder '1') aufrufen. Und das erfüllt alle Anforderungen eines konstanten Ausdrucks. – Angew

+0

@Angew In praktischer Hinsicht wird die Adresse von 'Parameters :: v 'jedoch vom Linker oder der Laufzeit festgelegt und dem Compiler nicht bekannt sein. Naiv, '* (Parameter :: v + 1)' als 'constexpr' wäre ein bisschen knifflig? –

+1

'C++ 11 [expr.const] §2,3' definieren die Anforderungen für konstante Ausdrücke, und die Array-Dereferenz verletzt keine von ihnen. Es ist also ein konstanter Ausdruck. – Angew