如何在constexpr函数中执行运行时断言?

How can I do a runtime assert in a constexpr function?

本文关键字:执行 运行时 断言 函数 constexpr      更新时间:2023-10-16

据我所知,constexpr函数可以在编译时执行,也可以在运行时执行,这取决于整个计算是否可以在编译时完成。

但是,您不能重载此函数以具有运行时和编译时对应的函数。

所以我的问题是,我如何放入一个运行时断言来确保运行时函数的执行与我的static_assert一起传递有效的参数?

Eric Niebler在c++ 11中的Assert和Constexpr中很好地讨论了这个问题,他指出在Constexpr函数中使用Assert在c++ 11中是不允许的,但在c++ 14中是允许的(作为Constexpr函数建议放宽约束的一部分),并提供了以下代码片段:

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

如果我们必须支持c++ 11,那么还有一些替代方案。最明显的一个是using throw,但正如他指出的那样,这会将本应不可恢复的错误变成可恢复的错误,因为您可以捕获异常。

他提出了一些建议:

  1. 使用noexcept指定符:

    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::terminate将被调用。

  2. 从异常类型的构造函数中调用std::quick_exit:

    struct assert_failure
    {
        explicit assert_failure(const char *sz)
        {
            std::fprintf(stderr, "Assertion failure: %sn", 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");}
            );
    }
    

可以抛出异常。如果在编译时从constexpr函数抛出异常,它基本上被视为静态断言失败。如果它发生在运行时,它将像往常一样只是一个异常。

在 周围传递constexpr对象

还相关:当计算constexpr时抛出异常时会发生什么?