据我所知,一个constexpr函数可以在编译时和运行时执行,这取决于整个评估是否可以在编译时完成。如何在constexpr函数中执行运行时断言?
但是,您不能重载此函数以具有运行时和编译时对应项。
所以我的问题是,我如何可以在运行时断言,以确保运行时功能的执行传递有效的参数与我的static_assert?
据我所知,一个constexpr函数可以在编译时和运行时执行,这取决于整个评估是否可以在编译时完成。如何在constexpr函数中执行运行时断言?
但是,您不能重载此函数以具有运行时和编译时对应项。
所以我的问题是,我如何可以在运行时断言,以确保运行时功能的执行传递有效的参数与我的static_assert?
埃里克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,那么有一些选择。显而易见的是使用抛出,但是他指出这会将不可恢复的错误转换为可恢复的错误,因为您可以捕获异常。
他提出了一些备选方案:
利用罚球与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 ::终止将被调用。
电话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函数中引发一个异常,它基本上被认为失败了一个静态断言。如果它在运行时发生,它将像往常一样是一个例外。
这个问题显示了代码示例,其中发生这种情况:Passing constexpr objects around
而且相关:What happens when an exception is thrown while computing a constexpr?
我也发现你可以直接在列表上下文中使用assert。 'constexpr bool in_range(int val,int min,int max){return(assert(min <= max),min <= val && val <= max); }'基本上,你必须做到这一点,以至于如果在失败时在constexpr上下文中使用它,它将永远不会得到非constexpr调用。这是有效的,因为assert是一个三元表达式的宏,它在失败时评估调用底层的非constexpr函数。 – Adrian
@Adrian有趣地注意到[逗号运算符只允许在C++ 11中的常量表达式中](http://stackoverflow.com/q/27324573/1708801)。 –
@Adrian,虽然这不会是可移植的,因为它依赖于标准没有涉及的assert的实现细节。 –