2015-07-03 5 views
14

C++ Primer (5. Auflage) auf Seite 240 hat einen Vermerk:Eine constexpr-Funktion ist nicht erforderlich, um einen konstanten Ausdruck zurückzugeben?

"A constexpr Funktion nicht erforderlich ist, einen konstanten Ausdruck zurückzukehren".

Es wurde eine Frage gestellt: can constexpr function return type be a non const?. Der Autor dieser Frage hat die Notiz falsch verstanden.

Aber was ist das richtige Verständnis davon (die Antworten auf den zitierten Beitrag klären die Verwirrung des Autors dieser Post, aber beantworten meine Frage nicht)?

+4

Danke Simon für die Formatierung der Frage so schön. Ich habe daraus neue Dinge gelernt. – AlwaysLearning

+2

Scott Meyers erklärt dieses Thema ziemlich gut in seinem neuen Buch, Effektive Moderne C++ – Alejandro

+0

@ Alejandro Welche Artikelnummer? – AlwaysLearning

Antwort

13

Eine (nicht Vorlage) constexpr Funktion muss mindestens einen Ausführungspfad haben, der einen konstanten Ausdruck zurückgibt; formal muss es Argumentwerte geben, so dass "ein Aufruf der Funktion [...] ein ausgewerteter Unterausdruck eines Kernkonstantenausdrucks sein könnte" ([dcl.constexpr]/5). Zum Beispiel (ibid.):

constexpr int f(bool b) { return b ? throw 0 : 0; }  // OK 
constexpr int f() { return f(true); }  // ill-formed, no diagnostic required 

int f(bool) Hier ist erlaubt, weil constexpr ihr Aufruf mit Argumentwert sein false einen konstanten Ausdruck liefert.

Es ist möglich, eine constexpr Funktion zu haben, die niemals einen konstanten Ausdruck zurückgeben kann, wenn es sich um eine Spezialisierung einer Funktionsvorlage handelt, die mindestens eine Spezialisierung haben kann, die einen konstanten Ausdruck zurückgibt. Nochmal mit dem obigen:

template<bool B> constexpr int g() { return f(B); } // OK 
constexpr int h() { return g<true>(); } // ill-formed, no diagnostic required 
+0

Was nützt es, 'g ()' als 'constexpr' zu deklarieren? Kannst du schreiben: constexpr int a = g (); '? Ich denke nicht, weil der Compiler den Initialisierungswert für 'a' zur Kompilierzeit nicht berechnen kann ... – AlwaysLearning

+0

@MeirGoldenberg richtig, aber Sie können schreiben 'constexpr int a = g ();', so der Standard erlaubt 'g()' zu "constexpr". – ecatmur

+0

Ah richtig, es wird nicht kompilieren, wenn ich "constexpr" in der Spezialisierung weglasse! Vielen Dank! – AlwaysLearning

15

Eine constexpr Funktion muss zurückgeben * muss einen Pfad haben, der einen konstanten Ausdruck zurückgibt, wenn alle Parameter konstante Ausdrücke sind. Das macht eigentlich Sinn. Beispiel:

constexpr int square(int i){ 
    return i*i; 
} 

std::array<int, square(2)> ia; //works as intended, constant expression 
int i; 
std::cin >> i; 
int j = square(i); //works even though i is not a constant expression 
std::array<int, square(i)> ia; //fails, because square does not (and cannot) 
           //return a constant expression 

* Korrektur durch chris.

+1

Ich stimme nicht zu. Solange es möglich ist, dass die Funktion einen konstanten Ausdruck zurückgibt, ist es in Ordnung. Es ist erlaubt, einen konstanten Ausdrucksparameter zu verwenden und einen nicht konstanten Ausdruck zurückzugeben, solange er einen konstanten Ausdruck ein anderes Mal zurückgibt (z. B. http://coliru.stacked-crooked.com/a/a0d9dcadc756749c). Dieses Argument ergibt sich aus der Frage, zu der das OP gehört. – chris

+1

Innerhalb der constexpr-Funktion werden die Parameter nicht als konstante Ausdrücke betrachtet. Also, sogar 'constexpr int foo (int i) {Rückkehr i; } 'gibt * keinen konstanten Ausdruck * zurück. Die Formulierung in C++ Primer ist ein bisschen dumm IMHO. Was der Standard erfordert, ist, dass man eine constexpr-Funktion innerhalb eines konstanten Ausdrucks aufrufen kann (es gibt Argumente, so dass die Funktion in einem konstanten Ausdruck aufgerufen werden kann). – dyp

Verwandte Themen