Range-based for loop on a dynamic array?
Solution 1:
To make use of the range-based for-loop you have to provide either begin()
and end()
member functions or overload the non-member begin()
and end()
functions.
In the latter case, you can wrap your range in a std::pair
and overload begin()
and end()
for those:
namespace std {
template <typename T> T* begin(std::pair<T*, T*> const& p)
{ return p.first; }
template <typename T> T* end(std::pair<T*, T*> const& p)
{ return p.second; }
}
Now you can use the for-loop like this:
for (auto&& i : std::make_pair(array, array + size))
cout << i << endl;
Note, that the non-member begin()
and end()
functions have to be overloaded in the std
namespace here, because pair
also resides in namespace std
. If you don't feel like tampering with the standard namespace, you can simply create your own tiny pair class and overload begin()
and end()
in your namespace.
Or, create a thin wrapper around your dynamically allocated array and provide begin()
and end()
member functions:
template <typename T>
struct wrapped_array {
wrapped_array(T* first, T* last) : begin_ {first}, end_ {last} {}
wrapped_array(T* first, std::ptrdiff_t size)
: wrapped_array {first, first + size} {}
T* begin() const noexcept { return begin_; }
T* end() const noexcept { return end_; }
T* begin_;
T* end_;
};
template <typename T>
wrapped_array<T> wrap_array(T* first, std::ptrdiff_t size) noexcept
{ return {first, size}; }
And your call site looks like this:
for (auto&& i : wrap_array(array, size))
std::cout << i << std::endl;
Example
Solution 2:
You can't use range-for-loop with dynamically allocated arrays, since compiler can't deduce begin and end of this array. You should always use containers instead of it, for example std::vector
.
std::vector<int> v(size);
for(const auto& elem: v)
// do something
Solution 3:
You can't perform a range based loop directly over a dynamically allocated array because all you have is a pointer to the first element. There is no information concerning its size that the compiler can use to perform the loop. The idiomatic C++ solution would be to replace the dynamically allocated array by an std::vector
:
std::vector<int> arr(size);
for(const auto& i : arr)
std::cout<< i << std::endl;
Alternatively, you could use a range type that provides a begin and end iterator based on a pointer and an offset. Have a look at some of the types in the boost.range library, or at the GSL span proposal (example implementation here, reference for C++20 proposed type here).
Note that a range based for loop does work for std::array
objects of fixes size plain arrays:
std::array<int,10> arr;
for(const auto& i : arr)
std::cout<< i << std::endl;
int arr[10] = .... ;
for(const auto& i : arr)
std::cout<< i << std::endl;
but in both cases the size needs to be a compile-time constant.