【问题标题】:error: conversion from std::chrono::time_point float to non-scalar type long int requested错误:请求从 std::chrono::time_point float 转换为非标量类型 long int
【发布时间】:2019-06-20 04:36:40
【问题描述】:

我有这段代码试图通过添加持续时间来创建新的 time_point:

// now
std::chrono::system_clock::time_point now = std::chrono::system_clock::now();
// duration
std::chrono::duration<float> duration(1.0f / 60.0f); // float in seconds
// now + duration
std::chrono::system_clock::time_point futureTime = now + duration;

但它给了我这个错误

error: conversion from 'std::chrono::time_point<std::chrono::_V2::system_clock, std::chrono::duration<float, std::ratio<1, 1000000000> > >' to non-scalar type 'std::chrono::_V2::system_clock::time_point {aka std::chrono::time_point<std::chrono::_V2::system_clock, std::chrono::duration<long int, std::ratio<1, 1000000000> > >}' requested
# it's over there in the distance --->

# ... again, with some manual formatting:
error:
    conversion from
    'std::chrono::time_point<std::chrono::_V2::system_clock,
                             std::chrono::duration<float, 
                                                   std::ratio<1, 1000000000> > >'
    to non-scalar type
    'std::chrono::_V2::system_clock::time_point
     {aka 
     std::chrono::time_point<std::chrono::_V2::system_clock,
                             std::chrono::duration<long int,
                                                   std::ratio<1, 1000000000> > >}'
    requested

经过一番严重的眯眼之后,第一个是float,第二个是long int。因此,now (long int) + duration (float) 给出了一个带有一些内部浮点持续时间的 time_point,我大概要求将其填充回默认的 long int 表示中。

我想最终将这个时间点传递给std::condition_variable::wait_until。如何强制转换为std::chrono::system_clock::time_point

如果这样做,我会失去什么样的精度(即它是否存储毫秒,在这种情况下我会失去一些 1 / 60)?

如果我不转换它,那么编写now + duration 返回的类型的简短方法是什么(是的,我可以使用 auto 但为了将其传递给函数)?

【问题讨论】:

  • "它是否存储毫秒数" 它存储你要求它存储的内容。另外,如果你想等待 1/60 秒,有什么理由不能只使用 wait_for,因为这正是它的目的?
  • 旁注:在 Windows 中让事情在 1/60 秒内发生可能很烦人,因为 Windows 使用 1/64 滴答声。
  • @NicolBolas std::chrono::system_clock::time_point 似乎隐含地将纳秒与std::ratio&lt;1, 1000000000&gt; 一起使用。我没有要求它这样做。我想等到 1/60 秒过去了,使用 wait_until 我可以继续调用它,直到我被打断时它超时,这与 wait_for 不同。

标签: c++ c++11 chrono


【解决方案1】:

您在问题中所做的分析基本上是正确的。并且有一些很好的方法可以使这项工作发挥作用。12

使用auto

// now
system_clock::time_point now = system_clock::now();
// duration
duration<float> duration(1.0f / 60.0f); // float in seconds
// now + duration
auto futureTime = now + duration;

futureTime 的类型是time_point&lt;system_clock, duration&lt;float, nano&gt;&gt;。也就是说,它是一个基于system_clocktime_point,存储了一个float代表的nanoseconds

这种类型可以和std::condition_variable::wait_until一起使用。

now + duration 转换回system_clock::time_point

// now
system_clock::time_point now = system_clock::now();
// duration
duration<float> duration(1.0f / 60.0f); // float in seconds
// now + duration
system_clock::time_point futureTime =
    time_point_cast<system_clock::duration>(now + duration);

time_point_cast&lt;duration&gt; 是您投射time_points 的方式。您必须明确指定您希望生成的time_point 具有的持续时间类型。生成的time_point 将继续基于相同的时钟。 结果将被截断(向零舍入)为下一个整数system_clock::duration(此平台上为nanoseconds)。

这种类型可以和std::condition_variable::wait_until一起使用。

now + duration 转回system_clock::time_point

system_clock::time_point futureTime = round<system_clock::duration>(now + duration);

这和前面的解决方案一样,除了这个四舍五入到最接近的整数nanoseconds,以及平局上的偶数nanosecondsstd::chrono::round 在 C++17 及更高版本中可用。这将给出最多与time_point_cast 不同的1ns 的结果。

如果您没有 C++17 但仍想使用round,请随时使用this one

这种类型可以和std::condition_variable::wait_until一起使用。

用积分算术精确地表示 1/60

// now
system_clock::time_point now = system_clock::now();
// duration
duration<int, std::ratio<1, 60>> duration{1}; // 1/60 of a second
// now + duration
auto futureTime = now + duration;

人们常说:

不可能精确地表示 1/60 秒。

但是您可以使用&lt;chrono&gt;。 :-) duration&lt;int, std::ratio&lt;1, 60&gt;&gt;1/60 秒为单位计数,使用 int 表示。 duration{1}1/60 秒。 duration{2}2/60 秒。等等。

auto真的在这里派上用场。 futureTime 的类型为:time_point&lt;system_clock, duration&lt;system_clock::rep, ratio&lt;1, 3'000'000'000&gt;&gt;&gt;。或者用英语:基于system_clocktime_point 使用具有system_clock::time_point 使用的任何表示类型的持续时间(通常是long long)和1/3nanoseconds.

事实证明,1/3nanoseconds最粗的精度,可以准确代表两者system_clock::period(此平台上为nanoseconds)和 1/60 秒。

&lt;chrono&gt; 会自动为您解决所有这些问题。要利用它,您只需使用auto

这种类型可以和std::condition_variable::wait_until一起使用。

如果您想回到基于纳秒的system_clock::time_point,也可以将duration&lt;int, std::ratio&lt;1, 60&gt;&gt;time_point_castround 结合使用。

总结

哪个最好?您必须根据应用程序中的其他因素来决定。通常,最好的方法是使其余代码更具可读性。

但是你有很多选择,它们都是不错的选择。他们都将使用std::condition_variable::wait_until

当您探索您的选项时,如果它无法编译,那是因为&lt;chrono&gt; 在编译时捕获了您的错误(就像第一个错误一样)。如果它可以编译(并且如果您没有使用 .count().time_since_epoch() 转义类型系统),那么它就可以工作了。


1 此问题中的答案假定system_clock::durationnanoseconds,如问题中所述。这仅适用于 gcc,在 Windows 和 macOS 上是不同的。

2 为了不迷失在冗长中,我将我的答案写成如下:

using namespace std::chrono;

在比赛中。它使事情如此更具可读性。

【讨论】:

    【解决方案2】:

    std::condition_variable::wait_until 看起来像这样:(cppreference)

    template< class Clock, class Duration >
    std::cv_status
        wait_until( std::unique_lock<std::mutex>& lock,
                    const std::chrono::time_point<Clock, Duration>& timeout_time );
    
    template< class Clock, class Duration, class Pred >    
    bool wait_until( std::unique_lock<std::mutex>& lock,
                     const std::chrono::time_point<Clock, Duration>& timeout_time,
                     Pred pred );
    

    您可以将任何time_point&lt;C, D&gt; 传递给它。它不一定是system_clock::time_point。而system_clock::time_point 就是time_point&lt;system_clock&gt;

    时钟的精确表示是实现定义的,但它必须是整数类型。 (1/60)s不能以整数为数字,秒为单位来精确表示。

    now + duration,其中now 属于time_point&lt;C, D1&gt; 类型,duration 属于duration&lt;R2, P2&gt; 类型,属于time_point&lt;C, std::common_type_t&lt;duration&lt;R1, P1&gt;, D2&gt;&gt; 类型。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-02-03
      • 2015-09-24
      • 2019-01-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多