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