2015-09-04 56 views
5

據我所知,一個constexpr函數可以在編譯時和運行時執行,這取決於整個評估是否可以在編譯時完成。如何在constexpr函數中執行運行時斷言?

但是,您不能重載此函數以具有運行時和編譯時對應項。

所以我的問題是,我如何可以在運行時斷言,以確保運行時功能的執行傳遞有效的參數與我的static_assert?

回答

4

埃裏克Niebler涵蓋這個問題以及在Assert and Constexpr in C++11,他指出,在一個constexpr函數中使用斷言是不允許的C++ 11但它是在C++ 14(As part of the Relaxing constraints on constexpr functions proposal)允許並提供了以下片段:

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

如果我們必須支持C++ 11,那麼有一些選擇。顯而易見的是使用拋出,但是他指出這會將不可恢復的錯誤轉換爲可恢復的錯誤,因爲您可以捕獲異常。

他提出了一些備選方案:

  1. 利用罰球與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!"); 
    } 
    

    如果有異常離開函數的std ::終止將被調用。

  2. 電話std::quick_exit從異常類的構造函數:

    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. 傳遞斷言一個異常類型的構造lambda表達式:

    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

我也發現你可以直接在列表上下文中使用assert。 'constexpr bool in_range(int val,int min,int max){return(assert(min <= max),min <= val && val <= max); }'基本上,你必須做到這一點,以至於如果在失敗時在constexpr上下文中使用它,它將永遠不會得到非constexpr調用。這是有效的,因爲assert是一個三元表達式的宏,它在失敗時評估調用底層的非constexpr函數。 – Adrian

+0

@Adrian有趣地注意到[逗號運算符只允許在C++ 11中的常量表達式中](http://stackoverflow.com/q/27324573/1708801)。 –

+0

@Adrian,雖然這不會是可移植的,因爲它依賴於標準沒有涉及的assert的實現細節。 –