2015-09-04 69 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的实现细节。 –