Warum lässt ein if constexpr diesen Kernfehler des konstanten Ausdrucks nicht verschwinden?

Lesezeit: 1 Minute

Warum lasst ein if constexpr diesen Kernfehler des konstanten Ausdrucks
StoryTeller – Unslander Monica

In Bezug auf diese Frage. Der Kernkonstantenausdruck, der zum Initialisieren von verwendet wird constexpr Variable y ist schlecht geformt. So viel ist gegeben.

Aber wenn ich versuche, den zu drehen if In ein if constexpr:

template <typename T>
void foo() {
    constexpr int x = -1;
    if constexpr (x >= 0){
        constexpr int y = 1 << x;
    }
}

int main(){
    foo<int>();
}

Der Fehler bleibt bestehen. Mit GCC 7.2 gibt es immer noch:

error: right operand of shift expression '(1 << -1)' is negative [-fpermissive]

Aber ich dachte, dass die semantische Prüfung auf einem verworfenen Zweig unvorgeformt bleiben sollte.

Einen Umweg über a machen constexpr Lambda hilft aber:

template <typename T>
void foo(){
    constexpr int x = -1;
    constexpr auto p = []() constexpr { return x; };
    if constexpr (x >= 0){
        constexpr int y = 1<<p();
    }
}

Der constexpr Spezifizierer an y scheint zu ändern, wie der verworfene Zweig überprüft wird. Ist dies das beabsichtigte Verhalten?


@max66 war so freundlich, andere Implementierungen zu überprüfen. Er berichtet, dass der Fehler sowohl mit GCC (7.2.0 / Head 8.0.0) als auch mit Clang (5.0.0 / Head 6.0.0) reproduzierbar sei.

  • Klingt nach einem Compiler-Bug. Haben Sie eine andere Implementierung versucht?

    – Schachar Shemesh

    1. Oktober 17 um 12:34 Uhr

  • @ShacharShemesh – Ich selbst habe es nicht. Aber das OP des Beitrags, den ich verlinkt habe, berichtet, dass sich Clang und MSVC gleich verhalten.

    – StoryTeller – Unslander Monica

    1. Oktober 17 um 12:35 Uhr

  • Ich bestätige das Problem mit clang++ 3.8.1

    – max66

    1. Oktober 17 um 12:35 Uhr


  • Von wanbox sehe ich, dass das Problem sowohl mit g++ (7.2.0 und Head 8.0.0) als auch mit clang++ (5.0.0 und Head 6.0.0) weiterhin besteht.

    – max66

    1. Oktober 17 um 12:45 Uhr

  • Ich glaube nicht, dass “der constexpr-Spezifizierer auf y zu ändern scheint, wie der verworfene Zweig überprüft wird”, weil das entfernt wird constexpr (einfaches Definieren von “int y = 1 << x;" Ich sehe keine Fehler mehr (ich nehme an, es ist richtig, wenn y ist initialisierte Laufzeit), aber ich sehe eine Warnung (unused variable y); also (wenn ich mich nicht irre) wird dieser Zweig kompiliert. Oder besser gesagt, ich finde das richtig im Sinne von mit constexpr y wird zur Kompilierzeit initialisiert (so 1 << x wird sofort geprüft) und ohne wird zur Laufzeit initialisiert.

    – max66

    1. Oktober 17 um 12:52 Uhr


1642299489 471 Warum lasst ein if constexpr diesen Kernfehler des konstanten Ausdrucks
Dietmar Kühl

Der Standard sagt nicht viel darüber aus verworfene Aussage eines if constexpr. Es gibt im Wesentlichen zwei Aussagen in [stmt.if] über diese:

  1. In einer einschließenden Vorlage werden verworfene Anweisungen nicht instanziiert.
  2. Namen, auf die von einer verworfenen Anweisung verwiesen wird, müssen nicht ODR definiert werden.

Beides trifft auf Ihre Verwendung nicht zu: Die Compiler beschweren sich zu Recht darüber constexpr wenn Initialisierung. Beachten Sie, dass Sie die Bedingung von einem Vorlagenparameter abhängig machen müssen, wenn Sie die nutzen möchten Instanziierung fehlschlagen: Wenn der Wert nicht von einem Vorlagenparameter abhängig ist, tritt der Fehler auf, wenn die Vorlage es ist definiert. Dieser Code schlägt beispielsweise immer noch fehl:

template <typename T>
void f() {
    constexpr int x = -1;
    if constexpr (x >= 0){
        constexpr int y = 1<<x;
    }
}

Allerdings, wenn Sie machen x abhängig vom Typ T es ist in Ordnung, auch wenn f wird mit instanziiert int:

template <typename T>
void f() {
    constexpr T x = -1;
    if constexpr (x >= 0){
        constexpr int y = 1<<x;
    }
}
int main() {
    f<int>();
}

  • Wie ich Kerrek kommentiere, ist das Beispiel in meinem Beitrag schlecht. Ich habe überprüft, ob es nach dem Verschieben des Codes in eine Vorlage bestehen bleibt. Der Basisfall gibt immer noch einen Fehler aus. Umleitung nicht. Ich habe das MCVE aktualisiert. Entschuldigung für die Unannehmlichkeiten.

    – StoryTeller – Unslander Monica

    1. Oktober 17 um 13:00 Uhr

  • @StoryTeller: Ich habe meine Antwort aktualisiert, um klarzustellen, dass nur die Instanziierung der Vorlage betroffen ist. Der Fehler, den Sie erhalten, tritt während auf Definition der Vorlage!

    – Dietmar Kühl

    1. Oktober 17 um 13:04 Uhr

  • @DietmarKühl: Sehr guter Punkt – die Überprüfung nicht abhängiger Konstruktionen ist Teil der Template-Definition, nicht einer Template-Instanziierung, daher ist die Nicht-Instanziierung des verworfenen Arms eigentlich ein Ablenkungsmanöver.

    – Kerrek SB

    1. Oktober 17 um 13:06 Uhr

  • Mmm.. Ja, ich fange an zu sehen, wo mein Verständnis schief gelaufen ist. Ich habe auch vergessen, dass, wenn keine Vorlagenspezialisierung gültig ist, das Programm für irgendein Argument falsch formatiert ist und keine Diagnose erforderlich ist. Dies hat meine Verwirrung vollständig behoben.

    – StoryTeller – Unslander Monica

    1. Oktober 17 um 13:10 Uhr

Beachten Sie dies für die Anweisung, die von verworfen wird Konstexpr Wenn:

Die verworfene Anweisung kann nicht für jede mögliche Spezialisierung falsch geformt sein:

Um das Problem zu beheben, können Sie die Anweisung abhängig vom Vorlagenparameter machen, z

template<typename T, int X> struct dependent_value { constexpr static int V = X; };

template <typename T>
void foo() {
    constexpr int x = -1;
    if constexpr (x >= 0){
        constexpr int y = 1 << dependent_value<T, x>::V;
    }
}

LIVE

Ich bin mir nicht sicher, warum Sie erwarten, dass der Zweig nicht überprüft wird. Das einzige Mal, wenn ein if-Zweig “nicht überprüft” wird, ist, wenn er Teil einer Vorlage ist und nicht instantiiert, gem [stmt.if]p2:

Wenn die Bedingung nach ihrer Instanziierung nicht wertabhängig ist, wird die verworfene Unteranweisung (falls vorhanden) während der Instanziierung einer einschließenden Vorlagenentität (Klausel 17) nicht instanziiert.

Ihr Code scheint sich nicht in einer Situation zu befinden, in der dies zutrifft.

  • Ich gebe zu, dass mein minimal reproduzierbares Beispiel schlecht ist. Der Fehler bleibt jedoch bestehen, nachdem der Code in eine Vorlage verschoben wurde (allerdings nicht mit einem Lambda). Also werde ich meine Frage aktualisieren. Tut mir leid, dass ich diese Antwort ungültig gemacht habe.

    – StoryTeller – Unslander Monica

    1. Oktober 17 um 12:56 Uhr

  • @StoryTeller: Keine Sorge. Es ist gut, neue Funktionen wie diese eingehend zu erkunden.

    – Kerrek SB

    1. Oktober 17 um 13:04 Uhr

.

499440cookie-checkWarum lässt ein if constexpr diesen Kernfehler des konstanten Ausdrucks nicht verschwinden?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy