如何在C++中对constexpr函数参数使用static_assert

How to use static_assert for constexpr function arguments in C++?

本文关键字:static assert 参数 函数 C++ 中对 constexpr      更新时间:2023-10-16

我的库中有几个简短的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);
}

assert现在工作了,g++已经实现了N3652,放松了对constexpr函数的约束。此状态页表示这已在gcc5中实现。

assert(在constexpr函数中)也适用于苹果公司提供的当前clang编译器-std=c++1y

目前,我在标准中没有看到任何东西可以保证assert将在constexpr函数中工作,这样的保证将是对标准的一个受欢迎的补充(至少对我来说是这样)。

更新

Richard Smith提请我注意Daniel Krügler提交的LWG 2234,该文件试图创建我上面提到的保证。这已被纳入C++17中。

抛出异常可能很有用,因为编译器在编译时知道没有抛出异常时会忽略运行时部分。

#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 );
}

实时示例

Daniel Frey的答案的一个改进是在constexpr函数上使用noexcept,将运行时错误转换为对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)

希望能有所帮助。