2015-09-04 6 views
5

Von dem, was ich verstehe, kann eine constexpr-Funktion sowohl zur Kompilierzeit als auch zur Laufzeit ausgeführt werden, abhängig davon, ob die gesamte Auswertung zur Kompilierzeit durchgeführt werden kann oder nicht.Wie kann ich eine Runtime-Assert in einer Constexpr-Funktion tun?

Sie können diese Funktion jedoch nicht überladen, um eine Laufzeit- und eine Kompilierzeit-Entsprechung zu haben.

Also meine Frage ist, wie kann ich in eine Laufzeit Assert, um sicherzustellen, dass die Ausführung der Laufzeitfunktion gültige Parameter zusammen mit meinem static_assert übergeben?

Antwort

4

Eric Niebler in Assert and Constexpr in C++11 dieses Problem gut abdeckt, weist er darauf hin, dass in nicht erlaubt in einer constexpr Funktion behaupten Verwendung C++ 11, aber es ist in C++ 14 (As part of the Relaxing constraints on constexpr functions proposal) erlaubt und liefert folgende Schnipsel:

constexpr bool in_range(int val, int min, int max) 
{ 
    assert(min <= max); // OOPS, not constexpr 
    return min <= val && val <= max; 
} 

Wenn wir C++ 11 unterstützen müssen, gibt es einige Alternativen. Die offensichtliche ist die Verwendung von throw, aber dies, wie er darauf hinweist, macht das, was ein nicht behebbarer Fehler sein sollte, in einen wiederherstellbaren Fehler, da Sie die Ausnahme abfangen können.

Er einige Alternativen vorschlagen:

  1. Wurf Verwendung mit dem noexcept specifier:

    constexpr bool in_range(int val, int min, int max) noexcept 
    { 
        return (min <= max) 
        ? min <= val && val <= max 
        : throw std::logic_error("Assertion failed!"); 
    } 
    

    wenn eine Ausnahme die Funktion std :: verlässt beenden aufgerufen.

  2. Anruf std::quick_exit aus dem Konstruktor eines Typs Ausnahme:

    struct assert_failure 
    { 
        explicit assert_failure(const char *sz) 
        { 
         std::fprintf(stderr, "Assertion failure: %s\n", sz); 
         std::quick_exit(EXIT_FAILURE); 
        } 
    }; 
    
    constexpr bool in_range(int val, int min, int max) 
    { 
        return (min <= max) 
         ? min <= val && val <= max 
         : throw assert_failure("min > max!"); 
    } 
    
  3. Pass einen Lambda-Ausdruck, der an den Konstruktor einer Ausnahmetyp behauptet:

    constexpr bool in_range(int val, int min, int max) 
    { 
        return (min <= max) 
         ? min <= val && val <= max 
         : throw assert_failure(
          []{assert(!"input not in range");} 
         ); 
    } 
    
+0

ich auch habe herausgefunden, dass Sie Assert direkt in einem Listenkontext verwenden können. consxpr bool in_range (int val, int min, int max) {return (assert (min <= max), min <= val && val <= max); } 'Grundsätzlich müssen Sie es so einrichten, dass es niemals zum Aufruf von non-constexpr gelangen kann, wenn es bei einem Fehler in einem consExpr-Kontext verwendet wird. Dies funktioniert, weil assert ein Makro für einen ternären Ausdruck ist, der bei Versagen die zugrunde liegende non-consxpr-Funktion aufruft. – Adrian

+0

@Adrian interessant zu beachten, dass [der Komma-Operator war nur in konstanten Ausdrücken in C++ 11 erlaubt] (http://stackoverflow.com/q/27324573/1708801). –

+0

@Adrian, obwohl das nicht portabel sein wird, da es sich auf das Implementierungsdetail von 'assert' verlässt, das nicht durch den Standard abgedeckt wird. –