0

Is there a way to achieve the same effect as this,

std::list<int> l(10);
std::iota(l.begin(), l.end(), -4);

With a regular int a[]?

Or, is the following the only way around:

for (iterator itr = begin; itr != end; ++itr)
    /* ... visit *itr here ... */
einpoklum
  • 118,144
  • 57
  • 340
  • 684
John Smith
  • 465
  • 4
  • 15
  • 38
  • 2
    just `std::iota( std::begin(a), std::end(a), -4 )`. I mean, if the latter was "the only way around", how would you get those iterators to loop with `for` in the first place? – underscore_d Sep 04 '20 at 10:18
  • Is that O(1) ? Right? – John Smith Sep 04 '20 at 10:19
  • Why wouldn't it be? Iterators to a plain array are just pointers. This seems like a dupe of [Cannot use .begin() or .end() on an array](https://stackoverflow.com/questions/14595285/cannot-use-begin-or-end-on-an-array) – underscore_d Sep 04 '20 at 10:20
  • ? What do you mean? – John Smith Sep 04 '20 at 10:25
  • You asked whether you can use a raw array with algorithms taking iterators, and then say 'or do I have to do it this way... using iterators'. You were shown how to get iterators to a raw array. Such iterators are just pointers, because what else could they be?. `iota` just assigns progressive values to each element, so that's O(1), and why would that be any different for a raw array than it is for an `std::list`? It's overall not clear exactly what you're asking or why. – underscore_d Sep 04 '20 at 10:28
  • 5
    `std::begin` and `std::end` for that array are equivalent to `&a[0]` and `&a[number_of_elements]` (which you could use since forever). It's not a coincidence that the interface of iterators has the same appearance as the interface of pointers. – molbdnilo Sep 04 '20 at 10:41

2 Answers2

6

C++11 added std::begin and std::end. Since then there is no difference:

std::list<int> l(10);
std::iota(std::begin(l),std::end(l), -4);
int a[10];
std::iota(std::begin(a),std::end(a), -4);
463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185
3

tl;dr: Wrap your array in a "span".

@idclev463035818's answer is the most straightforward thing to do. However, if you want to treat your array as a standard-library container in multiple contexts, consider wrapping the raw array in a span, like so:

auto a_ = std::span{a};

spans are lightweight reference-types to contiguous storage. They don't own their data, so you're not copying the array or anything. You can read more about spans here:

What is a "span" and when should I use one?

Anyway, now you can write:

std::iota(a_.begin(), a_.end(), -4);
for(x : a_) { do_stuff_with(x); }
auto c = std::ranges::count_if(a_, [](auto x) { return x > 3; });

and so on. Perhaps more importantly, the array "decays" into a pointer if you pass it to another function, and then you can no longer use std::begin() and std::end() on it; the span can be passed around, so it's more robust.

However - std::span is only in the standard beginning with C++20. Before that you can use the span implementation in the gsl-lite library, for example.

einpoklum
  • 118,144
  • 57
  • 340
  • 684