在基于范围的循环中迭代数组的一部分

8

在C++11的范围-based循环中,有没有一种方法只遍历数组的一部分?比如说我有一个int someArray [10000000],但我只想遍历前n个元素。因此,我不能简单地使用:

for(auto elem: someArray) {//doStuff}

有没有办法在使用基于范围的好处的同时限制循环范围?

1
在您看来,基于范围的好处有哪些?普通的for循环有什么问题吗? - Walter
5个回答

7

只需将范围适应为不同类型,其中 begin()end() 执行正确操作即可。

struct Slice {
  int* arr;
  size_t n;
  int* begin() { return arr; }
  int* end() { return arr + n; }
};

for(auto elem : Slice{someArray, 100}) {/*doStuff*/}

4
为什么不使用 size_t 来表示大小? - Neil Kirk
耸肩。如果你想的话可以使用它。与基于范围的for一起使用的数组几乎肯定是全局或自动的,因此不太可能太大以至于无法使用int索引。能够创建10e7个元素的数组的系统可能至少具有32位的int。如果没有,请使用更大的类型。 - Jonathan Wakely
6
为什么要写通常可以工作而不是总是可以工作的代码? - Neil Kirk
所以使用更大的类型。 - Jonathan Wakely

5

没有C++11的方法可以在不编写自己的包装器的情况下完成此操作。另一个选择是使用Range-V3,它具有view::slice请参见实时演示):

#include <iostream>

#include <range/v3/view.hpp>

int main() {
  int arr[10] = {1,2,3,4,5,6,7,8,9,10} ;

  using namespace ranges;

  auto rng = arr |  view::slice(3, 6);

  for( auto &item : rng )
  {
      std::cout << item << ", " ;
  }
  std::cout << std::endl ;
}

如果可以使用C++14,则GSL array_view是一个可行的选择:
gsl::array_view<int> av(arr+3,3) ;

for( auto &item : av )
{
    std::cout << item << ", " ;
}
std::cout << std::endl ;

gsl-lite提供了一个在C++11中工作的最小GSL实现。


3

使用C++20,可以使用std::span

for (auto elem : std::span(someArray).first(n))
  std::cout << elem;

2

目前标准中不支持这个功能。

在C++17中有一些正在开发中的功能可以实现这个,例如std::rangestd::array_view

但在此之前,只需使用老式的迭代器或索引for,它将是最易读的:

for(auto i = 0u; i < n; ++i)
{
    // do the stuffs on someArray[i]
}

0

基于范围的for循环遍历整个范围。你可以做的是存储一个额外的索引,在每次循环中进行检查。

size_t index = 0;
for(auto elem: someArray) 
{
   //doStuff

   if(index++ > n) break;
}

然而,我不认为使用这种方法比普通的for循环更有优势。

当然,你也可以在所需的子范围上使用std::for_each,但我仍然更喜欢传统的for循环。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接