據我所知,一個constexpr函數可以在編譯時和運行時執行,這取決於整個評估是否可以在編譯時完成。如何在constexpr函數中執行運行時斷言?
但是,您不能重載此函數以具有運行時和編譯時對應項。
所以我的問題是,我如何可以在運行時斷言,以確保運行時功能的執行傳遞有效的參數與我的static_assert?
據我所知,一個constexpr函數可以在編譯時和運行時執行,這取決於整個評估是否可以在編譯時完成。如何在constexpr函數中執行運行時斷言?
但是,您不能重載此函數以具有運行時和編譯時對應項。
所以我的問題是,我如何可以在運行時斷言,以確保運行時功能的執行傳遞有效的參數與我的static_assert?
埃裏克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,那麼有一些選擇。顯而易見的是使用拋出,但是他指出這會將不可恢復的錯誤轉換爲可恢復的錯誤,因爲您可以捕獲異常。
他提出了一些備選方案:
利用罰球與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 ::終止將被調用。
電話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!");
}
傳遞斷言一個異常類型的構造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");}
);
}
您可以拋出異常。如果在編譯時從一個constexpr函數中引發一個異常,它基本上被認爲失敗了一個靜態斷言。如果它在運行時發生,它將像往常一樣是一個例外。
這個問題顯示了代碼示例,其中發生這種情況:Passing constexpr objects around
而且相關:What happens when an exception is thrown while computing a constexpr?
我也發現你可以直接在列表上下文中使用assert。 'constexpr bool in_range(int val,int min,int max){return(assert(min <= max),min <= val && val <= max); }'基本上,你必須做到這一點,以至於如果在失敗時在constexpr上下文中使用它,它將永遠不會得到非constexpr調用。這是有效的,因爲assert是一個三元表達式的宏,它在失敗時評估調用底層的非constexpr函數。 – Adrian
@Adrian有趣地注意到[逗號運算符只允許在C++ 11中的常量表達式中](http://stackoverflow.com/q/27324573/1708801)。 –
@Adrian,雖然這不會是可移植的,因爲它依賴於標準沒有涉及的assert的實現細節。 –