std::adjacent_difference 和 std::chrono time_point
std::adjacent_difference with std::chrono time_point
考虑以下代码:
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形成一个仿射space。这类似于你不能添加两个指针,但你可以减去两个指针 - 你得到的不是指针,你得到一个 ptrdiff_t
.
adjacent_difference
算法不支持这样的仿射类型,因为给定一个范围 [a, b, c]
,输出被指定为 [a, b-a, c-b]
。这基本上行不通,因为 a
和 b-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;
});
摘自CppReference:
Computes the differences between the second and the first of each adjacent pair of elements of the range [first, last)
and writes them to the range beginning at d_first + 1
. An unmodified copy of *first
is written to *d_first
.
最后一句话让你误会了。
考虑以下代码:
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形成一个仿射space。这类似于你不能添加两个指针,但你可以减去两个指针 - 你得到的不是指针,你得到一个 ptrdiff_t
.
adjacent_difference
算法不支持这样的仿射类型,因为给定一个范围 [a, b, c]
,输出被指定为 [a, b-a, c-b]
。这基本上行不通,因为 a
和 b-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;
});
摘自CppReference:
Computes the differences between the second and the first of each adjacent pair of elements of the range
[first, last)
and writes them to the range beginning atd_first + 1
. An unmodified copy of*first
is written to*d_first
.
最后一句话让你误会了。