Eliminierung der if / else-Verzweigung in C ++ zur Kompilierungszeit

8

Im folgenden Codebeispiel ifhängt die Anweisung vom boolVorlagenparameter ab, bei dem es sich um eine Konstante zur Kompilierungszeit handelt. Compiler behandeln diesen Code unterschiedlich:

  • MSVC schlägt mit einem Verbindungsfehler fehl (was ich erwartet habe), da die Vorlagenfunktion in der elseVerzweigung nicht auf den trueWert der Vorlagenparameter spezialisiert ist (obwohl sie nie aufgerufen wird).

  • GCC und Clang werden beide ohne Probleme kompiliert und das Laufzeitverhalten ist korrekt. Dies liegt offensichtlich daran, dass sie die ifAnweisung beim Kompilieren auswerten und nicht verwendete Zweige vor dem Verknüpfen entfernen.

Die Frage ist, welches Verhalten standardkonform ist (oder ist es ein undefiniertes Verhalten und beide sind auf ihre Weise korrekt)?

#include <iostream>

template<const bool condition>
struct Struct
{
    void print()
    {
        if (condition)
        {
            std::cout << "True\n";
        }
        else
        {
            printIfFalse();
        }
    }

private:
    void printIfFalse();
};

template <>
void Struct<false>::printIfFalse()
{
    std::cout << "False\n";
}

int main()
{
    Struct<true> withTrue{};
    withTrue.print();

    Struct<false> withFalse{};
    withFalse.print();

    return 0;
}
Igor Tolmachov
quelle
4
Hallo, nicht das, wonach du suchst, aber du kannst es dir ansehenif constexpr
Martin Morterol
1
Beide Compiler haben recht. Pedantisch ist dies ein nicht spezifiziertes Verhalten. Der C ++ - Standard legt nicht fest, was hier passiert.
Sam Varshavchik
@SamVarshavchik Noch mehr pedantisch, dann ist es nicht definiertes Verhalten (UB). Aber in der realen Welt ist es ein Fehler oder es funktioniert. Keine UB zur Laufzeit.
Neugieriger

Antworten:

11

Alle Compiler verhalten sich korrekt.

Ihr Programm ist schlecht geformt, es ist keine Diagnose erforderlich , da Sie es Struct<true>::printIfFalsedurch die Instanziierung des Struct<true>::print()vom Anruf in erforderlichen Programms verwenden withTrue.print();. Eine Funktion, die außerhalb einer verworfenen Anweisung verwendet wird, muss eine Definition im Programm haben, siehe [basic.def.odr] / 4 , andernfalls ist das Programm fehlerhaft , keine Diagnose erforderlich .

Eine verworfene Anweisung erhalten Sie, wenn Sie sie if constexprin einer Vorlage verwenden und sich die Anweisung nicht im ausgewählten Zweig befindet. Was Sie also tun können, um das Programm wohlgeformt zu machen, ist, es if constexpranstelle von zu verwenden if. Dies ist eine C ++ 17-Funktion.

Nussbaum
quelle