假设我想以my_func()
的间隔定期呼叫CALL_PERIOD
auto last_call_time = CHRONO_NEGATIVE_INFINITY;
while (true)
{
if (std::chrono::system_clock::now() - last_call_time > CALL_PERIOD)
{
last_call_time = std::chrono::system_clock::now();
my_func();
}
}
什么合适的CHRONO_NEGATIVE_INFINITY
使得行
std::chrono::system_clock::now() - last_call_time > CALL_PERIOD
在第一次运行时总会评估true
吗?
我尝试过time_point::min()
,但这似乎不起作用
答案 0 :(得分:4)
拥有std::optional
这样的类型的主要原因之一是,这样我们就不必像选择特定值来表示“不是值”一样受黑客攻击:
std::optional<std::chrono::system_clock::time_point> last_call_time;
while (true)
{
auto curr = std::chrono::system_clock::now()
if (!last_call_time || (curr - *last_call_time) > CALL_PERIOD)
{
last_call_time = std::chrono::system_clock::now();
my_func();
}
}
如果您无法使用C ++ 17,并且/或者您只是对使用旧的选择特殊值的技巧感到困惑,则可以获取时钟的rep
类型并计算最小值可能的整数:
using sys_clock = std::chrono::system_clock;
constexpr auto min_int = std::numeric_limits<sys_clock::rep>::min();
constexpr sys_clock::duration min_duration(min_int);
sys_clock::time_point min_time(min_duration);
当然,min_time
仍然是有效时间,因此它与float
的任何“无穷大”表示形式不同。
答案 1 :(得分:2)
没有time_point::infinity
等效项的理由是time_point
是围绕算术类型的简单包装。简单的包装器导致性能最高的代码。同样的道理也表明,在特殊情况下,time_point::infinity
实际上确实存在!
让我进一步阐述一下完全令人困惑的第一段...
system_clock::time_point
是duration
周围的简单包装。确切的duration
未指定,但我们只能说是nanoseconds
。 nanoseconds
是一个简单的包装,它封装了一个64位带符号整数(例如long long
)。
long long
没有+/- INFINITY
的表示形式。但是它确实有一个最小值:-9223372036854775808。
将这个值放入duration
(例如nanoseconds
)的快捷方式是nanoseconds::min()
,将这个值放入system_clock::time_point
的快捷方式是system_clock::time_point::min()
但是,当您这样做时,它是普通的旧有符号整数溢出的邀请。毕竟:
cout << (10 - numeric_limits<long long>::min() > 1) << '\n';
溢出并打印出0
(假)。这就是为什么:
auto CHRONO_NEGATIVE_INFINITY = system_clock::time_point::min();
没有用。
有几种方法可以使代码正常工作。哪种最适合您的应用程序取决于您。但是现在<chrono>
有点神秘了,您可以更好地做出决定。
也许最简单的方法是将CHRONO_NEGATIVE_INFINITY
设置为不太负面的值,以免冒险:
auto CHRONO_NEGATIVE_INFINITY = std::chrono::system_clock::now() - CALL_PERIOD;
C ++ 20对system_clock
的时代是1970-01-01的现有做法进行了标准化,因此这是另一种可能性(适用于C ++ 11):
// Set CHRONO_NEGATIVE_INFINITY to 1970-01-01 00:00:00 UTC
auto CHRONO_NEGATIVE_INFINITY = std::chrono::system_clock::time_point{};
但是,可以说由于某种原因,您确实确实需要一个无限期的time_point
。您也可以这样做,只需要多做一些工作。 float
和double
也是算术类型,它们 do 的表示形式为INFINITY
!因此,您可以从其中一种类型中构建time_point
。
using dsec = std::chrono::duration<double>;
using tp_dsec = std::chrono::time_point<std::chrono::system_clock, dsec>;
auto CHRONO_NEGATIVE_INFINITY = tp_dsec{dsec{-INFINITY}};
第一行将dsec
命名为double-based-seconds。第二行使用tp_dsec
作为表示,使system_clock
为基于time_point
的{{1}}的名称。然后第三行只是将负无穷大填充到dsec
中。测试时,其余代码将隐式转换为基于双精度的tp_dsec
和time_point
。
答案 2 :(得分:1)
如果您这样重写测试:
auto last_call_time = std::chrono::system_clock::min();
...
if (std::chrono::system_clock::now() - CALL_PERIOD > last_call_time)
你不应该溢出。