2014-09-27 101 views
8

我在庫中有幾個簡短的constexpr函數,它們執行一些簡單的計算。我在運行時和編譯時都使用它們。對constexpr函數斷言的替代

我想在這些函數的主體中執行一些斷言,但assert(...)constexpr函數中無效,並且static_assert(...)不能用於檢查函數參數。

例子:

constexpr int getClamped(int mValue, int mMin, int mMax) noexcept 
{ 
    assert(mMin <= mMax); // does not compile! 
    return mValue < mMin ? mMin : (mValue > mMax ? mMax : mValue); 
} 

有沒有辦法來檢查是否功能在運行時正在執行或編譯時間常數和執行assert只有當它在運行時執行?

constexpr int getClamped(int mValue, int mMin, int mMax) noexcept 
{ 
    assert_if_runtime(mMin <= mMax); 
    return mValue < mMin ? mMin : (mValue > mMax ? mMax : mValue); 
} 
+1

@dasblinkenlight:我的意思是'static_assert' [在這種情況下沒有意義](http://ideone.com/6yjdAE)。 – 2014-09-27 08:28:29

+0

(免責聲明:我是一個noob,在現實生活中從未使用過constexpr。)基於我最初的Google搜索,除非您的編譯器支持[N3652](http://www.open-std.org/jtc1/sc22/ wg21/docs/papers/2013/n3652.html),它放鬆了C++ 11'constexpr',它不能做你所要求的。一旦這個可用,你將能夠拋出一個異常,例如'std :: range_error'來代替'static_assert'。你可以用[Clang 3.4 with std = C++ 14](http://clang.llvm.org/cxx_status.html)來試試你的手。 – rwong 2014-09-27 09:06:00

+0

你的聲明在'-std = C++ 1y'模式下對Clang來說不是真的,assert會工作得很好。如果您僅限於該標準,您應該重新使用「C++ 11」。 – TemplateRex 2014-09-27 22:14:45

回答

4

我相信只要g ++執行N3652, Relaxing constraints on constexpr functionsassert就可以爲你工作。目前,this status page表示尚未實施。

assert在蘋果發佈的當前clang編譯器中工作(在constexpr函數中),其中-std=c++1y

在這個時候,我沒有看到標準中確保assert將在constexpr函數中工作的標準,這樣的保證將是標準(至少是我)的一個受歡迎的補充。

更新

理查德·史密斯把我的注意由DanielKrügler它試圖創建我指的是上面的保證LWG 2234

+1

+1我一直在使用斷言所有的constexpr代碼,我很滿意 – TemplateRex 2014-09-27 22:15:28

+0

不,它不會工作,因爲'assert'宏必須最終調用'abort'(通常通過__assert_fail等中間函數),這不是一個constexpr函數。 – o11c 2014-09-27 22:27:23

+0

@ o11c如果'assert'總是調用'abort',它會被打破。 – Potatoswatter 2014-09-27 22:30:58

8

因爲編譯器會忽略運行時部分時,它知道在編譯時的異常沒有拋出拋出異常可能是有用的。

#include <cassert> 

constexpr int getClamped(int mValue, int mMin, int mMax) 
{ 
    return (mMin <= mMax) ? 
      (mValue < mMin ? mMin : (mValue > mMax ? mMax : mValue)) : 
      throw "mMin must be less than or equal to mMax"; 
} 

int main(int argc, char** argv) 
{ 
    // These two work: 
    static_assert(getClamped(42, 0, 100) == 42, "CT"); 
    assert(getClamped(argc, 0, 100) == argc); 

    // Fails at compile-time: 
    // static_assert(getClamped(42, 100, 0) == 42, "CT"); 

    // Fails at run-time: 
    // assert(getClamped(argc, 100, 0) == argc); 
} 

Live example

+0

在玩了一段時間後(試圖找到一種方法來使'constexpr'工作超載),我認爲這是最好的/唯一的方法來做到這一點。但從鉗功能拋出的想法讓我感到恐慌...... – 2014-09-27 10:33:33

5

丹尼爾·弗雷的回答細化使用noexceptconstexpr函數打開運行時錯誤到調用std::terminate。斷言失敗是不可恢復的;他們應該立即停止這個過程。把它們變成例外是一個非常糟糕的主意。

#include <exception> 
#include <stdexcept> 

struct assert_failure 
    : std::logic_error 
{ 
    explicit assert_failure(const char *sz) 
     : std::logic_error(sz) 
    {} 
}; 

constexpr bool in_range(int i, int j, int k) noexcept 
{ 
    return (i <= j && j <= k) ? true : throw assert_failure("input not in range"); 
} 

int main(int argc, char* argv[]) 
{ 
    constexpr bool b1 = in_range(0, 4, 5); // OK! 
    constexpr bool b2 = in_range(0, 6, 5); // Compile-time error! 
    bool b3 = in_range(0, 4, argc);  // May or may not terminate the process 
} 

我的運行時錯誤的樣子:

terminate called after throwing an instance of 'assert_failure' 
    what(): input not in range 
Aborted (core dumped) 

希望幫助。

+0

+1我明確地刪除了'noexcept',但它確實有它的用途,所以謝謝指出。當然,這是一個你需要做出的決定,在我平常的工作環境中,終止這個過程是我們試圖避免的,但我對失敗提前表示出同情,並且很難做到:) – 2014-09-30 19:22:49