Reputation: 47619
Suppose I have two iterators begin
and end
of type Iterator and some predicate predicate
(stored in obj
). I want to implement method some_collection()
o that I can write
for(auto element: obj.get_collection()) {
do_smth()
}
so that it's work only on elements which satisfy predicate (i.e eqiuvalent to smth like this)
for (auto element: range(begin, end)) {
if (predicate(element)) {
do_smth();
}
}
Approximate implementation I have in mind is the following (pseudocode):
struct Wrapper {
op++() {
do {
++value;
while (!predicate(*value));
}
op*() {
return *value;
}
op !=(Iterator other) {
return value != other.value;
}
Iterator value;
}
Where begin()
of returned object will be like
value = begin;
while (!predicate(*value)) ++value;
return Wrapper(value)
and end()
is just Wrapper(end)
What I don't like in this implementation:
I could iterate before each dereference (to fix 2nd and 3rd points) but it will make != end
check harder (either I need to decrement end in advance or use increment in check itself which means passing input range two times during the cycle)
I don't have specific language version requirements and even interested in implementations using not yet approved. But C++11 would be the greatest
I don't have specific requirements for iterator category supported. I believe Mine will work with ForwardIterators
.
I'm interested in both understandability of the code and its efficiency.
Any solution that is closer to silver bullet? :)
Upvotes: 2
Views: 208
Reputation: 3733
You could use a BOOST filter_iterator
. Here is the example from the linked page:
struct is_positive_number {
bool operator()(int x) { return 0 < x; }
};
int main()
{
int numbers_[] = { 0, -1, 4, -3, 5, 8, -2 };
const int N = sizeof(numbers_)/sizeof(int);
typedef int* base_iterator;
base_iterator numbers(numbers_);
// Example using filter_iterator
typedef boost::filter_iterator<is_positive_number, base_iterator>
FilterIter;
is_positive_number predicate;
FilterIter filter_iter_first(predicate, numbers, numbers + N);
FilterIter filter_iter_last(predicate, numbers + N, numbers + N);
std::copy(filter_iter_first, filter_iter_last, std::ostream_iterator<int>(std::cout, " "));
std::cout << std::endl;
// Example using make_filter_iterator()
std::copy(boost::make_filter_iterator<is_positive_number>(numbers, numbers + N),
boost::make_filter_iterator<is_positive_number>(numbers + N, numbers + N),
std::ostream_iterator<int>(std::cout, " "));
std::cout << std::endl;
// Another example using make_filter_iterator()
std::copy(
boost::make_filter_iterator(
std::bind2nd(std::greater<int>(), -2)
, numbers, numbers + N)
, boost::make_filter_iterator(
std::bind2nd(std::greater<int>(), -2)
, numbers + N, numbers + N)
, std::ostream_iterator<int>(std::cout, " ")
);
std::cout << std::endl;
return boost::exit_success;
}
Upvotes: 1