什么是std :: chrono :: time_point与std :: numeric_limits :: infinity()等效?

时间:2019-12-03 03:19:30

标签: c++ chrono

假设我想以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(),但这似乎不起作用

3 个答案:

答案 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_pointduration周围的简单包装。确切的duration未指定,但我们只能说是nanosecondsnanoseconds是一个简单的包装,它封装了一个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。您也可以这样做,只需要多做一些工作。 floatdouble也是算术类型,它们 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_dsectime_point

答案 2 :(得分:1)

如果您这样重写测试:

auto last_call_time = std::chrono::system_clock::min();
...
if (std::chrono::system_clock::now() - CALL_PERIOD > last_call_time)

你不应该溢出。