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

穿精又带淫゛_ 提交于 2019-12-23 07:46:28

问题


From what I understand, a constexpr function can be executed at compile time as well as runtime, depending on if the entire evaluation can be done at compile time or not.

However, you cannot overload this function to have a runtime and a compile time counterpart.

So my question is, how can I put in a runtime assert to ensure that the execution of the runtime function is passed valid parameters along with my static_assert?


回答1:


Eric Niebler covers this issue well in 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) and provides the following snippet:

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

If we have to support C++11 then there are some alternatives. The obvious one is the using throw but this as he points out this turns what should be a unrecoverable error into a recoverable one since you can catch the exception.

He suggest some alternatives:

  1. Using throw with the 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!");
    }
    

    if an exception leaves the function std::terminate will be called.

  2. Call std::quick_exit from the constructor of an exception type:

    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. Pass a lambda expression that asserts to the constructor of an exception type:

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



回答2:


You can throw an exception. If an exception is thrown at compile time from a constexpr function, it basically counts as failing a static assert. If it happens at runtime, it will just be an exception as usual.

This question shows a code example where this happens: Passing constexpr objects around

Also related: What happens when an exception is thrown while computing a constexpr?



来源:https://stackoverflow.com/questions/32401256/how-can-i-do-a-runtime-assert-in-a-constexpr-function

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!