假设我有Iterator类型的两个迭代器begin
和end
以及一些谓词predicate
(存储在obj
中)。我想实现我可以编写的方法some_collection()
o
for(auto element: obj.get_collection()) {
do_smth()
}
这样它只能在满足谓词的元素上工作(即像这样的smth等效)
for (auto element: range(begin, end)) {
if (predicate(element)) {
do_smth();
}
}
我想到的近似实现是以下(伪代码):
struct Wrapper {
op++() {
do {
++value;
while (!predicate(*value));
}
op*() {
return *value;
}
op !=(Iterator other) {
return value != other.value;
}
Iterator value;
}
返回对象的begin()
类似
value = begin;
while (!predicate(*value)) ++value;
return Wrapper(value)
和end()
只是Wrapper(end)
在此实施中我不喜欢什么:
我可以在每次取消引用之前进行迭代(以修复第2点和第3点),但它会使!= end
检查更加困难(要么我需要提前减少结果,要么在检查中使用增量,这意味着将输入范围传递两次在周期中)
我没有特定的语言版本要求,甚至对尚未批准的实施感兴趣。但是C ++ 11将是最伟大的
我没有支持迭代器类别的特定要求。我相信我会与ForwardIterators
合作。
我对代码的可理解性及其效率感兴趣。
任何更接近银弹的解决方案? :)
答案 0 :(得分:1)
您可以使用BOOST filter_iterator
。以下是链接页面中的示例:
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;
}