2015-12-15 14 views
18

Das folgende Stück Code kompiliert unter clang ++ 3.7.0, wird aber von g ++ 5.3.1 verweigert. Beide haben -std=c++14 Option. Welcher Compiler ist korrekt? Weiß jemand, wo im Standard darüber gesprochen wird? Vielen Dank.Throw in constexpr Funktion

#include <stdexcept> 
using namespace std; 

constexpr int f(int n) { 
    if (n <= 0) throw runtime_error(""); 
    return 1; 
} 

int main() { 
    char k[f(1)]; 
} 

Ausgabe

[hidden] g++ -std=c++14 c.cpp 
c.cpp: In function ‘constexpr int f(int)’: 
c.cpp:7:1: error: expression ‘<throw-expression>’ is not a constant-expression 
} 
^ 
[hidden] clang++ -std=c++14 c.cpp 
[hidden] 
[hidden] g++ -v 
Using built-in specs. 
COLLECT_GCC=/usr/bin/g++ 
COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-redhat-linux/5.3.1/lto-wrapper 
Target: x86_64-redhat-linux 
Configured with: ../configure --enable-bootstrap --enable-languages=c,c++,objc,obj-c++,fortran,ada,go,lto --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-shared --enable-threads=posix --enable-checking=release --enable-multilib --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-linker-build-id --with-linker-hash-style=gnu --enable-plugin --enable-initfini-array --disable-libgcj --with-isl --enable-libmpx --enable-gnu-indirect-function --with-tune=generic --with-arch_32=i686 --build=x86_64-redhat-linux 
Thread model: posix 
gcc version 5.3.1 20151207 (Red Hat 5.3.1-2) (GCC) 
[hidden] 
[hidden] clang++ -v 
clang version 3.7.0 (http://llvm.org/git/clang.git 2ddd3734f32e39e793550b282d44fd71736f8d21) 
Target: x86_64-unknown-linux-gnu 
Thread model: posix 
Found candidate GCC installation: /usr/lib/gcc/x86_64-redhat-linux/3.4.6 
Found candidate GCC installation: /usr/lib/gcc/x86_64-redhat-linux/5.3.1 
Selected GCC installation: /usr/lib/gcc/x86_64-redhat-linux/5.3.1 
Candidate multilib: .;@m64 
Candidate multilib: 32;@m32 
Selected multilib: .;@m64 
+0

die Standard-doesn sage nicht, dass es nicht werfen kann, soweit ich sehen kann –

+0

Es wurde darauf hingewiesen, dass es einen GCC-Bug-Bericht darüber gibt, keine Work-Arounds zur Verfügung gestellt. –

Antwort

15

Klirren korrekt ist, beachten Sie die HEAD revision of gcc accepts auch diesen Code akzeptiert. Dies ist eine wohlgeformte constexpr-Funktion, solange es einen Wert für das Argument (die Argumente) gibt, der es ermöglicht, die Funktion als einen konstanten Kernausdruck auszuwerten. In Ihrem Fall ist 1 solch ein Wert.

Dies wird in dem Entwurf ++ 14 Standard-Teil C abgedeckt 7.1.5 Der constexpr Spezifizierer [dcl.constexpr], die uns sagt, was in einer constexpr Funktion erlaubt ist:

Die Definition einer constexpr Funktion erfüllen soll die folgenden Einschränkungen:

  • 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 von nicht-Literal-Typ oder von statischen oder Gewinden st orage duration oder für welche keine Initialisierung durchgeführt wird.

keine Beschränkung auf throw und es sagt auch (Hervorhebung von mir):

Für eine nicht-Vorlage, nicht ausgefallene constexpr Funktion oder eine nicht-Vorlage, nicht-voreingestellt, nicht-erben conexpr-Konstruktor, wenn keine Argumentwerte vorhanden sind, sodass ein Aufruf der Funktion oder des Konstruktors eine Auswertung sein könnte ted Teilausdruck einer Kernkonstante Ausdruck (5.19), das Programm ist schlecht gebildet; nein Diagnose erforderlich.

und unterhalb dieses Absatzes wir das folgende Beispiel haben, ähnlich wie bei Ihnen:

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

throw ist in einem Kern konstanten Ausdruck ist nicht zulässig, die im Abschnitt bedeckt ist 5.19[expr.const ] Absatz 2 der besagt:

Ein bedingter Ausdruck e ist ein Kern konstanter Ausdruck, es sei denn die Auswertung von e, nach den Regeln der abstrakten Maschine (1,9), einer der folgenden Ausdrücke

und enthält die folgende Kugel bewerten würde:

  • ein Wurf-Ausdruck (15.1).

und so f würde in einem Kern konstanten Ausdruck nicht verwendet werden, wenn n <= 0.

aktualisieren

Wie TemplateRex darauf hinweist, gibt es zwei gcc Bugs berichtet hierzu:

TemplateRex stellt auch die Updates nicht angewendet werden zu 5.3.0 und sind nur im Kofferraum. Nein, Workarounds sind vorhanden.

4

Wie von Shafik Yaghmour gezeigt, ist es ein gcc-Bug, der hoffentlich in v6 behoben wird.

Bis dahin können Sie die c++11 constexpr Stil zurückkehren:

constexpr auto foo(int n) -> int 
{ 
    return n <= 0 ? throw runtime_error("") : 1; 
} 

es jedoch eine bessere Abhilfe, noch all die c++14 constexpr Erweiterungen beibehalten:

// or maybe name it 
// throw_if_zero_or_less 
constexpr auto foo_check_throw(int n) -> void 
{ 
    n <= 0 ? throw std::runtime_error("") : 0; 
} 

constexpr auto foo(int n) -> int 
{ 
    foo_check_throw(n); 

    // C++14 extensions for constexpr work: 
    if (n % 2) 
    return 1; 
    return 2; 
} 
Verwandte Themen