这段代码怎么能成为constexpr? (标准::计时)

时间:2015-11-15 04:44:31

标签: c++ c++14 constexpr chrono c++17

在标准论文P0092R1中,Howard Hinnant写道:

template <class To, class Rep, class Period,
          class = enable_if_t<detail::is_duration<To>{}>>
constexpr
To floor(const duration<Rep, Period>& d)
{
    To t = duration_cast<To>(d);
    if (t > d)
        --t;
    return t;
}

此代码如何工作?问题是operator--上的std::chrono::duration不是constexpr操作。它被定义为:

duration& operator--();

然而这段代码编译,并在编译时给出了正确的答案:

static_assert(floor<hours>(minutes{3}).count() == 0, "”);

该怎么做?

2 个答案:

答案 0 :(得分:10)

答案是并非所有编译时例程中的操作都必须是constexpr;只编译在编译时执行的

在上面的示例中,操作是:

hours t = duration_cast<hours>(d);
if (t > d) {} // which is false, so execution skips the block
return t;

所有这些都可以在编译时完成。

另一方面,如果您尝试:

static_assert(floor<hours>(minutes{-3}).count() == -1, "”);

它会产生编译时错误(使用clang):

error: static_assert expression is not an integral constant expression
        static_assert(floor<hours>(minutes{-3}).count() == -1, "");
                      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
note: non-constexpr function 'operator--' cannot be used in a constant expression
                        --t;
                        ^
note: in call to 'floor(minutes{-3})'
        static_assert(floor<hours>(minutes{-3}).count() == -1, "");

编写constexpr代码时,您必须通过代码考虑所有路径

P.S。您可以这样修复建议的floor例程:

template <class To, class Rep, class Period,
          class = enable_if_t<detail::is_duration<To>{}>>
constexpr
To floor(const duration<Rep, Period>& d)
{
    To t = duration_cast<To>(d);
    if (t > d)
        t = t - To{1};
    return t;
}

答案 1 :(得分:-1)

根据n3597n3652的规则,constexpr函数中的表达式本身不必是常量表达式,只要它们不修改全局可见状态即可

有一个

的例子
constexpr int f(int a) {
  int n = a;
  ++n;                  // '++n' is not a constant expression
  return n * a;
}
int k = f(4);           // OK, this is a constant expression.
                        // 'n' in 'f' can be modified because its lifetime
                        // began during the evaluation of the expression.

很可能这些是Howard Hinnant在撰写您提到的论文时遵循的规则。

要使用问题中的duration<T>代码,operator--必须成为constexpr函数。由于constexpr对图书馆的更改不是最终的,因此很容易理解霍华德如何依赖这样的改变。