迭代容器的前 n 个元素 - std::span vs views::take vs ranges::subrange
Iterating over first n elements of a container - std::span vs views::take vs ranges::subrange
因此,在 c++ 20 中,我们获得了许多新功能,包括范围、跨度等。现在,如果我需要迭代一个容器,但只需要第一个 n
元素,什么是最合适的方法,幕后是否有任何实际差异?或者返回到带有索引的常规 for 循环可能是更好的主意,因为这些示例的性能可能较低?
for (const auto &e: elements | std::ranges::views::take(n)) {
// do stuff
}
for (const auto &e: std::span(elements.begin(), n)) {
// do stuff
}
for (const auto &e: std::ranges::subrange(elements.begin(), elements.begin() + n)) {
// do stuff
}
views::take
是最通用的,它几乎适用于任何范围,例如input_range
、output_range
以及更细化的范围。
std::span
仅适用于contiguous_range
.
虽然ranges::subrange
也是泛型,但是由于需要通过elements.begin() + n
获取迭代器的bound,这就要求elements
必须是random_access_range
.
另外值得注意的是,在P1739之后,views::take
会根据范围的类型得到一个“合适”的范围类型,即当范围为span
,就会returnspan
,当string_view
,就会returnstring_view
,当subrange
,就会return subrange
,当为iota_view
时,会return iota_view
.
因此,在 c++ 20 中,我们获得了许多新功能,包括范围、跨度等。现在,如果我需要迭代一个容器,但只需要第一个 n
元素,什么是最合适的方法,幕后是否有任何实际差异?或者返回到带有索引的常规 for 循环可能是更好的主意,因为这些示例的性能可能较低?
for (const auto &e: elements | std::ranges::views::take(n)) {
// do stuff
}
for (const auto &e: std::span(elements.begin(), n)) {
// do stuff
}
for (const auto &e: std::ranges::subrange(elements.begin(), elements.begin() + n)) {
// do stuff
}
views::take
是最通用的,它几乎适用于任何范围,例如input_range
、output_range
以及更细化的范围。std::span
仅适用于contiguous_range
.虽然
ranges::subrange
也是泛型,但是由于需要通过elements.begin() + n
获取迭代器的bound,这就要求elements
必须是random_access_range
.
另外值得注意的是,在P1739之后,views::take
会根据范围的类型得到一个“合适”的范围类型,即当范围为span
,就会returnspan
,当string_view
,就会returnstring_view
,当subrange
,就会return subrange
,当为iota_view
时,会return iota_view
.