Mar*_*low 7 c++ constexpr c++-chrono c++14 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;
}
Run Code Online (Sandbox Code Playgroud)
这段代码怎么样?问题是,operator--a std::chrono::duration不是constexpr操作.它被定义为:
duration& operator--();
Run Code Online (Sandbox Code Playgroud)
然而,这段代码编译,并在编译时给出正确的答案:
static_assert(floor<hours>(minutes{3}).count() == 0, "”);
Run Code Online (Sandbox Code Playgroud)
那是怎么回事?
Mar*_*low 10
答案是,并非编译时例程中的所有操作都必须是constexpr; 只有在编译时执行的那些.
在上面的示例中,操作是:
hours t = duration_cast<hours>(d);
if (t > d) {} // which is false, so execution skips the block
return t;
Run Code Online (Sandbox Code Playgroud)
所有这些都可以在编译时完成.
另一方面,如果您尝试:
static_assert(floor<hours>(minutes{-3}).count() == -1, "”);
Run Code Online (Sandbox Code Playgroud)
它会给出一个编译时错误说(使用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, "");
Run Code Online (Sandbox Code Playgroud)
在编写constexpr代码时,您必须考虑代码中的所有路径.
PS你可以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;
}
Run Code Online (Sandbox Code Playgroud)