2015-12-10 12 views
10

Ich habe dieses Beispiel aus §5.19/2 in N4140:Soweit ich das beurteilen kann, ist die folgende Funktion nicht constexpr, aber der Code kompiliert in clang und g ++. Was vermisse ich?

constexpr int incr(int &n) { 
    return ++n; 
} 

Soweit ich sagen kann, ist dies nicht eine Funktion constexpr ist. Aber der Snippet kompiliert in clang und g ++. Siehe live example. Was fehlt mir hier?

+0

Ich bin mir nicht sicher, aber braucht "constexpr", für Funktionen, nur einen Fall, für den es zur Kompilierzeit auf etwas optimiert werden kann? – VermillionAzure

+0

Ich bekomme einen Kompilierfehler, wenn ich versuche, * 'incr()' zu verwenden, um eine 'constexpr'-Variable zu initialisieren. –

Antwort

9

In C++ 14 die Regeln für constexpr Funktion waren entspannt und das Papier N3597: Relaxing constraints on constexpr functions. Das Papier geht in die Grundlagen und die Auswirkungen, und es enthält die folgenden (emphasis Mine):

wie in C++ 11 wird das Schlüsselwort constexpr markieren Funktionen verwendet, welche die Umsetzung erforderlich ist, während der zur Bewertung Übersetzung, wenn sie aus einem Kontext verwendet werden, in dem ein konstanter Ausdruck benötigt wird. Jeder gültige C++ - Code ist in constexpr-Funktionen zulässig, einschließlich der Erstellung und Änderung lokaler Variablen und fast aller Anweisungen, , mit der Einschränkung, dass eine constexpr-Funktion innerhalb eines konstanten Ausdrucks verwendet werden kann. Ein konstanter Ausdruck kann immer noch Nebenwirkungen haben, die für die Bewertung und deren Ergebnis lokal sind.

und:

Eine Handvoll syntaktischen Beschränkungen constexpr Funktionen sind beibehalten:

  • ASM-Deklarationen nicht zulässig sind.
  • try-blocks und function-try-blocks sind nicht erlaubt.
  • Deklarationen von Variablen mit statischer und Thread-Speicherdauer haben einige Einschränkungen (siehe unten).

und wir können dies in N4140 Abschnitt behandelt finden 7.1.5[dcl.constexpr] die sagt:

Die Definition einer constexpr Funktion soll die folgenden Bedingungen erfüllen:

  • es soll nicht virtuell sein (10.3);

  • Der Rückgabetyp muss ein Literaltyp sein;

  • jeder seiner Parametertypen muss ein Literaltyp sein;

  • seine Funktion Körper wird sein = löschen = default oder eine Verbindung-Anweisung, die nicht

    • eine asm-Definition,

    • eine goto-Anweisung,

    • enthält
    • ein try-block oder

    • eine definition einer variablen vom nicht-literalen typ oder von statisch oder thread st orage duration oder für welche keine Initialisierung durchgeführt wird.

Das letzte Beispiel zeigt, wie incr in einem constexpr verwendet werden:

constexpr int h(int k) { 
    int x = incr(k); // OK: incr(k) is not required to be a core 
        // constant expression 
    return x; 
} 

constexpr int y = h(1); // OK: initializes y with the value 2 
         // h(1) is a core constant expression because 
         // the lifetime of k begins inside h(1) 

und der Regel, dass the lifetime of k begins inside h(1) bedeckt ist:

  • Modifikation ein Objekt (5.17, 5.2.6, 5.3.2) unle ss wird auf einen nichtflüchtigen Wert des Literaltyps angewendet, der sich auf ein nichtflüchtiges Objekt bezieht, dessen Lebensdauer mit der Auswertung von e begann;

Die Formulierung in 7.1.5[dcl.constexpr] zeigt uns, warum incr eine gültige constexpr ist:

Für eine nicht-Vorlage, nicht ausgefallene constexpr Funktion oder eine nicht-Vorlage consExpr-Konstruktor, wenn keine Argumentwerte vorhanden sind, sodass ein Aufruf der Funktion oder des Konstruktors ein ausgewerteter Unterausdruck eines konstanten Kernausdrucks sein könnte (5.19), ist das Programm schlecht gebildet; nein Diagnose erforderlich.

Wie das modifizierte Beispiel von T.C.:

constexpr int& as_lvalue(int&& i){ return i; } 

constexpr int x = incr(as_lvalue(1)) ; 

zeigt, können wir incr als subexpression eines Kern konstanten Ausdruck und deshalb ist es nicht schlecht gebildet verwenden in der Tat.

+0

Ich bin mir nicht sicher, ob ich verstehe, was Ihr Problem mit der aktuellen Formulierung ist . –

+0

@ T.C. Nun, 'incr 'ist kein * Unterausdruck * von' h (1) 'und ich sehe keinen Fall, in dem' incr 'ein Teilausdruck eines konstanten Ausdruckes sein könnte und trotzdem gültig wäre. Fehle ich hier etwas? –

+0

@ShafikYaghmour Ich versuche deine Antwort zu verstehen. Es scheint mir, dass Sie sagen, dass die Funktion 'incr()' nicht 'consxpr' ist, weil sie nicht §7.1.5/5 erfüllt, aber keine Diagnose erforderlich ist. In gewissem Sinne sind clang und g ++ konform.Ist das richtig? – Ayrosa

7

Soweit ich das beurteilen kann, ist dies keine constexpr Funktion.

Warum sagst du das? Das Beispiel aus §5.19/2 lautet:

constexpr int g(int k) { 
    constexpr int x = incr(k); // error: incr(k) is not a core constant 
           // expression because lifetime of k 
           // began outside the expression incr(k) 
    return x; 
} 

incr(k) kein Kern konstanter Ausdruck ist bedeutet nicht, kann nicht incr kein constexpr Funktion sein.

Unter C++ 14 der constexpr Regeln ist es möglich, incr in einem constexpr Kontext zu verwenden, zum Beispiel:

constexpr int incr(int& n) { 
    return ++n; 
} 

constexpr int foo() { 
    int n = 0; 
    incr(n); 
    return n; 
} 

Es sei denn, es geradezu unmöglich ist, für den Körper der Funktion constexpr (zum Beispiel zu sein, Unerwarteter Aufruf einer non-constexpr-Funktion), hat der Compiler keinen Grund, zum Zeitpunkt der Definition einen Fehler zu erzeugen.

Eine constexpr-Funktion kann sogar Pfade/Zweige im Körper enthalten, die nicht constexpr sind. Solange sie nie in einem conexpr Kontext genommen werden, erhalten Sie keinen Fehler. Zum Beispiel:

constexpr int maybe_constexpr(bool choice, const int& a, const int& b) { 
    return choice ? a : b; 
} 

constexpr int a = 0; 
int b = 1; 
static_assert(maybe_constexpr(true, a, b) == 0, "!"); 

live example

+0

Warum dachte ich, Incr() 'ist nicht" constexpr "? Weil sein Argument nicht "const" ist, und auch nicht "const". – Ayrosa

+0

Und mehr: die Funktion 'Ñncr()' hat Nebenwirkungen, es ändert den Wert seines Arguments. – Ayrosa

+0

... was unter C++ 14 erlaubt ist * entspannte constexpr * -Regeln – melak47