Fire Yoshi
Fire Yoshi

Reputation: 91

How can I replace this for loop with an STL implementation?

I have this little for-loop here (variables and types renamed):

vector<Iterator> validIterators;

for (auto itr = someStartIterator; itr != someVector.end(); itr++)
{
  if (itr->foo() && itr->bar())
    validIterators.push_back(itr); // Notice that I'm not deferencing the iterator when adding it to the vector
}

...

for (const auto& itr : validIterators)
{
  // Do stuff with the iterator explicitly (e.g. std::distance),
  // and not the object that it points (at least not at first).
}

Is there any way to use the STL <algorithm> functions to make something "cleaner"? I can't use Boost in that context, nor C++20 ranges or range-v3.

Thank you in advance.

Upvotes: 1

Views: 884

Answers (2)

Ted Lyngmo
Ted Lyngmo

Reputation: 117298

The standard library algorithms uses iterators to work on some underlying data and the iterators themselves are not available through the standard library algorithms. You'll have to write your own algorithm for that.

Example:

template<class Iterator, class Func>
std::vector<Iterator> get_valid_iterators(Iterator Begin, Iterator End, Func f) {
    std::vector<Iterator> rv;

    for(; Begin != End; ++Begin)
        if(f(Begin)) rv.push_back(Begin); // f is functor that can validate the iterator

    return rv;
}

Usage:

auto vi = get_valid_iterators(container.begin(), container.end(),
                              [](auto& it) { return it->foo() && it->bar(); });

Upvotes: 1

Nicol Bolas
Nicol Bolas

Reputation: 473352

Algorithms, by their nature, operate on sequences of values. They interface with these sequence of values through an intermediary object called an "iterator". But this is, from the implementation's perspective, an implementation detail. A necessary one, to be sure, but it is still not really part of the algorithm.

As such, algorithms do not typically expose the iterators to user-provided functors. std::for_each passes the functor a value extracted from the iterator, not the iterator itself. std::sort's predicate compares pairs of values, not pairs of iterators. std::copy_if copies values based on a predicate which is provided a value. And so forth. Even the range-based for loop itself doesn't expose the iterators.

Algorithms manipulate values through their iterators, not the iterators themselves.

Your best bet is to do the loop manually and fold the "act on the iterator" part into the conditional testing part.

for (auto itr = someStartIterator; itr != someVector.end(); itr++)
{
  if (itr->foo() && itr->bar())
  {
    // Do stuff with the `itr` explicitly (e.g. std::distance).
  }
}

Upvotes: 1

Related Questions