I am wondering if there is something available in C++ which helps us to iterate over the two nested loops while using auto
. Say like, I would want to compare an array element with all other elements forward. This is how we do it traditionally:
std::vector<int> vec {1, 2, 3, 4};
for (int i = 0; i < vec.size(); ++i)
{
for (int j = i + 1; j < vec.size(); ++j)
{
if (vec[i] == vec[j]) {}
// Compares 1 with 2, 3 and 4
// Compares 2 with 3 and 4
}
}
The intention is to use auto
in order to achieve this.
std::vector<int> vec{1, 2, 3, 4};
for (<auto>& i : vec)
// ^^^^^^^
{
// What should I write here so that I compare only the forward elements?
}
We can probably use something like this:
for (auto it = vec.begin(); it != vec.end(); ++it)
{
for (auto jt = it + 1; jt != vec.end(); ++jt)
{
// Do a comparison here.
}
}
And the third snapshot again writes more code. I am looking to get more insights on the plain second snapshot.
Mentioned in the question itself.
I am wondering if there is something available in C++ which helps us to iterate over the two nested loops while using
auto
.
Not exactly what you wished for; However, with std::ranges::iota_view
(Since c++20), you could write nested range-based for
loops like follows:
#include <ranges> // std::ranges::iota_view
for (const auto i : std::views::iota(0u, std::size(vec)))
{
for (const auto j : std::views::iota(i + 1u, std::size(vec)))
{
if (vec[i] == vec[j])
{
// .....
}
}
}
See a live demo in godbolt.org
Additionally, this enables you to have i
and j
be const
over the loop scope.
Side note: For compilers older than C++20, one could easily implement an iterator that act exactly like std::ranges::iota_view
.
In c++20, something like this, perhaps?
#include <span>
/*...*/
std::size_t offset = 0;
for (auto &i: vec)
{
for (auto &j: std::span(vec).subspan(++offset))
{
if (i == j) {}
// Compares 1 with 2, 3 and 4
// Compares 2 with 3 and 4
}
}
offset
is guaranteed to be always <= vec.size()
, hence subspan()
is well defined.
If you don't want to introduce a new variable, this would also work, but might produce more verbose assembly and look quite unusual:
for (auto &i: vec)
{
for (auto &j: std::span(vec).subspan(&i - vec.data() + 1))
{
if (i == j) {}
// Compares 1 with 2, 3 and 4
// Compares 2 with 3 and 4
}
}
For the shortest assembly, having the outer loop iterate over a span already is the best, so that the span doesn't have to be constructed at each outer iteration.
std::span span(vec);
std::size_t offset = 0;
for (auto &i: span)
{
for (auto &j: span.subspan(++offset))
{
if (i == j) {}
// Compares 1 with 2, 3 and 4
// Compares 2 with 3 and 4
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With