如何在 constexpr 函数中执行运行时断言?
How can I do a runtime assert in a constexpr function?
据我了解,constexpr 函数可以在编译时和运行时执行,具体取决于整个计算是否可以在编译时完成。
但是,您不能重载此函数以使其具有运行时和编译时对应项。
所以我的问题是,如何放入运行时断言以确保运行时函数的执行与我的 static_assert 一起传递有效参数?
你可以抛出异常。如果在编译时从 constexpr 函数抛出异常,它基本上算作静态断言失败。如果它发生在运行时,它会像往常一样只是一个异常。
这个问题展示了发生这种情况的代码示例:Passing constexpr objects around
还相关:What happens when an exception is thrown while computing a constexpr?
Eric Niebler 在 Assert and Constexpr in C++11, he points out that using assert in a constexpr function is not allowed in C++11 but it is allowed in 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,那么有一些替代方案。最明显的是 using throw 但正如他所指出的那样,这会将不可恢复的错误变成可恢复的错误,因为您可以捕获异常。
他提出了一些替代方案:
使用 throw 和 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::terminate 将被调用。
从异常类型的构造函数中调用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 函数可以在编译时和运行时执行,具体取决于整个计算是否可以在编译时完成。
但是,您不能重载此函数以使其具有运行时和编译时对应项。
所以我的问题是,如何放入运行时断言以确保运行时函数的执行与我的 static_assert 一起传递有效参数?
你可以抛出异常。如果在编译时从 constexpr 函数抛出异常,它基本上算作静态断言失败。如果它发生在运行时,它会像往常一样只是一个异常。
这个问题展示了发生这种情况的代码示例:Passing constexpr objects around
还相关:What happens when an exception is thrown while computing a constexpr?
Eric Niebler 在 Assert and Constexpr in C++11, he points out that using assert in a constexpr function is not allowed in C++11 but it is allowed in 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,那么有一些替代方案。最明显的是 using throw 但正如他所指出的那样,这会将不可恢复的错误变成可恢复的错误,因为您可以捕获异常。
他提出了一些替代方案:
使用 throw 和 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::terminate 将被调用。
从异常类型的构造函数中调用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");} ); }