I want to achieve something like the pseudo-code below:
string foo; // or vector<int> foo;
auto itr = bar? foo.begin() : foo.rbegin();
auto end = bar? foo.end() : foo.rend();
for ( ; itr != end; ++itr) {
// SomeAction ...
}
That is, I want to set itr to be either a forward iterator or the reverse iterator, depending on some condition bar, to scan in forward or reverse direction.
Apparently code like that won't work, since forward iterator and reverse iterator has different type.
Note that I don't want to split into two loops, as those code like // SomeAction will be duplicated.
How can I do that? Answers using C++11 and/or before are preferred.
Also, please elaborate if string and vector have different solutions.
I would put the logic in a two-iterator function:
<template typename Iter>
void do_stuff(Iter first, Iter last)
{
for(; first != last; ++first)
{
// Do logic
}
}
bar ? do_stuff(foo.begin(), foo.end()) : do_stuff(foo.rbegin(), foo.rend());
The forward and reverse iterators are different types for most if not all containers, so unfortunately if it is a runtime decision, they can not simply be assigned to the same variable through the use of auto.
One option is to move the use of them into a template function:
template<class Iterator> void loop(Iterator begin, Iterator end)
{
for (auto itr = begin; itr != end; ++itr) { ... }
}
if (bar) loop(foo.begin(), foo.end());
else loop(foo.rbegin(), foo.rend());
In newer versions of C++ (C++14 and newer, so not C++11) the loop function can be a lambda, by using auto as the parameter type.
auto loop = [](auto begin, auto end)
{
for (auto itr = begin; itr != end; ++itr) { ... }
};
Another option, although somewhat more involved would be to make a wrapper type that can contain either an iterator or reverse iterator, and acts like an iterator itself with at least the comparison, increment and dereference operators.
I don't want to split into two loops, as those code like // SomeAction will be duplicated.
Put the action into a lambda.
auto lambda = [&](char &val) // `ElementType &`
{
// ...
};
if (bar)
{
for (auto &val : foo)
lambda(val);
}
else
{
for (auto it = foo.rbegin(); it != foo.rend(); it++)
lambda(*it);
}
Alternatively, use indices rather than iterators. This will only work with containers that allow random access.
std::size_t i, end, step;
if (bar)
{
i = 0;
end = foo.size();
step = 1;
}
else
{
i = foo.size() - 1;
end = -1;
step = -1;
}
for (; i != end; i += step)
{
// ...
}
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