是的,您可以创建一个自定义迭代器来满足您的需求,但目前使用标准 C++ 创建自定义迭代器有点乏味。它看起来像这样:
template <typename Itr, typename F>
struct ConditionalIterator {
Itr itr;
Itr end;
F condition;
using value_type = typename Itr::value_type;
using difference_type = typename Itr::difference_type;
using pointer = typename Itr::pointer;
using reference = typename Itr::reference;
using iterator_category = std::forward_iterator_tag;
ConditionalIterator() = default;
ConditionalIterator(Itr itr, Itr end, F condition): itr(itr), end(end), condition(condition) {}
bool operator!=(const ConditionalIterator &other) const { return other.itr != itr; }
reference operator*() const { return *itr; }
pointer operator->() const { return &(*itr); }
ConditionalIterator& operator++() {
for (; ++itr != end;) {
if (condition(*itr))
break;
}
return *this;
}
ConditionalIterator operator++(int) {
ConditionalIterator ret(*this);
operator++();
return ret;
}
};
然后您可以创建类似于您要求的conditional_begin 和conditional_end 辅助函数。唯一的问题是std::vector::insert 期望两个迭代器具有相同的类型。如果我们使用 lambda 作为我们的条件,那么这将是我们的条件迭代器类型的一部分。所以我们需要将 lambda 传递给两个辅助函数,以便它们返回具有匹配类型的迭代器:
template <typename C, typename F>
auto conditional_begin(const C &source, F f) {
return ConditionalIterator<typename C::const_iterator, F>(source.begin(),
source.end(), f);
}
template <typename C, typename F>
auto conditional_end(const C &source, F f) {
return ConditionalIterator<typename C::const_iterator, F>(source.end(),
source.end(), f);
}
你可以用这样的 lambda 调用:
auto condition = [](const auto &a) { return a != 3; };
target.insert(std::begin(target),
conditional_begin(source, std::ref(condition)),
conditional_end(source, std::ref(condition)));
Live demo.
我的crude tests 显示,在这种情况下,这最终比简单地使用copy_if 和back_inserter 快得多,因为std::vector::insert 在插入之前首先计算出要分配多少内存。仅使用back_inserter 将导致多次内存分配。性能差异将取决于评估条件的成本。您可以通过在使用copy_if 之前使用count_if 保留足够的空间来获得相同的加速:
auto count = static_cast<size_t>(std::count_if(source.begin(),
source.end(), condition));
target.reserve(target.size() + count);
std::copy_if(source.begin(),
source.end(),
std::back_inserter(target), condition);
Live demo.