c++ - std::adjacent_difference 与 std::chrono time_point

标签 c++ c++20 chrono

考虑以下代码:

int main()
{
    std::vector<std::chrono::steady_clock::time_point> time;
    time.push_back(std::chrono::steady_clock::now());
    std::this_thread::sleep_for(std::chrono::milliseconds(4));
    time.push_back(std::chrono::steady_clock::now());
    std::this_thread::sleep_for(std::chrono::milliseconds(7));
    time.push_back(std::chrono::steady_clock::now());
    std::vector<std::chrono::duration<double>> diffs;
    std::adjacent_difference(time.begin(),time.end(),std::back_inserter(diffs));
}
它不会编译(关于不匹配类型的丑陋模板错误消息)。
当我尝试切换到输入错误消息( std::chrono::time_point<std::chrono::_V2::steady_clock, std::chrono::duration<long, std::ratio<1, 1000000000>>> )时,错误消息会四处移动。
我的假设是算法不起作用,因为减去 2 个时间点的结果不是时间点,即伪代码中的这一行是相互矛盾的。
template<class InputIt, class OutputIt>
constexpr // since C++20
OutputIt adjacent_difference(InputIt first, InputIt last, 
                             OutputIt d_first)
{
    if (first == last) return d_first;
 
    typedef typename std::iterator_traits<InputIt>::value_type value_t;
    value_t acc = *first;  
    *d_first = acc; // <-----------------------------------------------------  1
    while (++first != last) {
        value_t val = *first;
        *++d_first = val - std::move(acc); // std::move since C++20  <-------- 2
        acc = std::move(val);
    }
    return ++d_first;
}
所以我有两个问题:
  • 我的猜测正确吗?
  • 最简单的修复方法是什么? Best 我能想到的丑
    从时间点转换为持续时间作为中间步骤。

  • 尽管 chrono 是 C++11,但我标记了这个 C++20,因为我对任何 C++20 解决方案持开放态度,尽管我更喜欢它们不是范围,因为它们没有在我的编译器中实现。

    最佳答案

    My assumption is that algorithm does not work because result of substracting 2 timepoints is not a timepoint


    实际上,减去两个 time_point 不会产生 time_point - 它会产生 duration 。在 <chrono> 中, duration s 和 time_point s 形成仿射空间。这类似于您不能添加两个指针,但您可以减去两个指针 - 而您得到的不是指针,而是 ptrdiff_tadjacent_difference 算法不支持这样的仿射类型,因为给定范围 [a, b, c] 输出被指定为 [a, b-a, c-b] 。这基本上是行不通的,因为 ab-a 具有不同的、不可转换的类型。
    最简单的方法可能是使用 range-v3:
    zip_with(minus(), time, time | drop(1))
    
    产生您实际想要的相邻差异 - 不包括第一个值( time_point ),因此您只会获得 duration 的范围。

    有一个 transform() 的两个范围版本,我总是忘记(感谢 Conor)。这也有效:
    std::transform(time.begin(), std::prev(time.end()), std::next(time.begin()),
        std::back_inserter(diffs), std::minus());
    
    这基本上是 adjacent_difference 的“正确”版本。在 C++20 中,这可以更清楚一点:
    std::ranges::transform(time, time | std::views::drop(1),
        std::back_inserter(diffs), std::minus());
    

    你也可以完全滥用 adjacent_find :
    std::adjacent_find(time.begin(), time.end(), [&](auto t1, auto t2){
        diffs.push_back(t2 - t1);
        return false;
    });
    

    关于c++ - std::adjacent_difference 与 std::chrono time_point,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62538995/

    相关文章:

    c++ - 优化模块化算法的代码

    C++链表赋值运算符问题

    c++ - Boost 共享指针数组

    c++ - static constexpr 指向具有多重继承的成员函数向下转型的指针

    c++ - 使用chrono C++与时间进行比较

    ubuntu - 来自类的计时计时器类传递方法不起作用

    c++ - 如何将字符转换为整数

    c++ - 强制 format_to_n 使用终止零

    c++ - C++20 中的 `constinit` 是什么?

    c++ - 如何在不受系统时间变化影响的情况下测量耗时