模仿conditional_back_inserter这样的东西的最佳方式

Best way to emulate something like conditional_back_inserter?

本文关键字:最佳 方式 conditional back inserter 模仿      更新时间:2023-10-16

我想在下面的代码中用算法替换循环

int numbers[] = { ... };
vector<int> output;
for( int* it = numbers+from; it != numbers+to ; ++it ) 
{
    int square = func( *it );
    if( predicate(square) )
    {
         output.push_back(square);
    }
}

该程序旨在转换值,并在出现条件时将其复制到目标。

  • 我无法使用std::copy_if,因为这不会应用转换
  • 我不能使用std::transform,因为它缺少谓词
  • 由于转换变量的中间副本,编写transform_copy_if()甚至不是一个好主意

看起来我唯一的希望就是创建一个conditional_back_insert_iterator。然后我可以打一个相当不错的电话,比如:

int numbers[] = { ... };
vector<int> output;
std::transform(numbers+from, numbers+to, 
               conditional_back_inserter(predicate, output),   
               func);

这种解决方案是治疗此类病例的最佳方法吗我甚至无法在谷歌上搜索条件插入器,所以我担心自己走错了路。

我还可以想象我可以实现一个替代解决方案,比如

std::copy_if( transform_iterator<func>(numbers+from), 
              transform_iterator<func>(numbers+to), 
              back_inserter(output) );

(这让我想起了boost中的*filter_iterators*示例)但这并不能提供可读性。

我认为创建自己的迭代器是可行的:

#include <iostream>
#include <vector>
#include <iterator>
#include <functional>
template<class T>
class conditional_back_insert_iterator
    : public std::back_insert_iterator<std::vector<T>>
{
private:
    using Base       = std::back_insert_iterator<std::vector<T>>;
    using Container  = std::vector<T>;
    using value_type = typename Container::value_type;
public:
    template<class F>
    conditional_back_insert_iterator(Container& other, F&& pred)
        :  Base(other), c(other), predicate(std::forward<F>(pred))
    { }
    conditional_back_insert_iterator<T>& operator*()
    { return *this; }
    conditional_back_insert_iterator<T>&
        operator=(const value_type& val) const
    {
        if (predicate(val))
            c.push_back(val);
        return *this;
    }
    conditional_back_insert_iterator<T>&
        operator=(value_type&& val) const
    {
        if (predicate(val))
            c.push_back(std::move(val));
        return *this;
    }
private:
    Container& c;
    std::function<bool (const value_type&)> predicate;
};
template<
    class Container,
    class F,
    class value_type = typename Container::value_type
>
conditional_back_insert_iterator<value_type>
    conditional_back_inserter(Container& c, F&& predicate)
{
    return conditional_back_insert_iterator<value_type>(c, std::forward<F>(predicate));
}
int main()
{
    std::vector<int> v{1, 2, 3, 4, 5, 6, 7, 8, 9};
    std::vector<int> to;
    auto is_even = [] (int x) { return (x % 2) == 0; };
    std::copy(v.begin(), v.end(), conditional_back_inserter(to, is_even));
}

这是我的尝试。

#include <algorithm>
#include <iostream>
#include <iterator>
#include <vector>
template <class Container, class Pred>
class conditional_insert_iterator 
    : public std::iterator< std::output_iterator_tag, void, void, void, void >
{
public:
    explicit conditional_insert_iterator(Container& c, Pred p) : container(&c), pred(p) {}
   conditional_insert_iterator& operator=(typename Container::const_reference value) {
    if (pred(value))
        container->push_back(value);
    return *this;
}
    conditional_insert_iterator& operator*() {return *this;}
    conditional_insert_iterator& operator++() {return *this;}
    conditional_insert_iterator& operator++(int) {return *this;}
private:
    Container* container;
    Pred pred;
};
template< class Container, class Pred>
conditional_insert_iterator<Container, Pred> conditional_inserter( Container& c, Pred pred )
{
    return conditional_insert_iterator<Container, Pred>(c, pred);
}
using namespace std;
int main()
{
    vector<int> in = { 1, 2, 3, 4, 5, 6 };
    vector<int> out;
    transform(in.begin(), in.end(),
              conditional_inserter(out, [](int i) { return i%2 == 0;}), 
              [](int i) { return i + 2;});
    for (auto i : out)
        cout << i << "n"; 
    return 0;
}