2014-09-27 55 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