代码之家  ›  专栏  ›  技术社区  ›  Johan Lundberg

如何将back\u插入器与转换相结合,C++

  •  8
  • Johan Lundberg  · 技术社区  · 7 年前

    如何包装输出计算器,例如 back_inserter_iterator 有了转变? 考虑

    std::vector<double> xx;
    std::vector<double> yy;
    std::vector<double> diff;
    auto ba = std::back_inserter(diff);
    std::set_difference(xx.begin(), xx.end(), yy.begin(), yy.end(), ba);
    

    我想应用一个自由函数 f(double) g(std::vector<double>::iterator) 在推回差异向量之前:

    具体来说,我如何存储diff元素(或迭代器)的地址,而不是元素本身的地址。

    std::vector<double&> diff;
    auto baAdr = ??? std::back_inserter( ??? (diff)); 
    std::set_difference(xx.begin(), xx.end(), yy.begin(), yy.end(), baAdr);
    

    出于性能原因(实际数据很大),我不想构建临时向量 std::transform 从中。它也不适用于不可复制、可移动的类型。

    我可以使用boost。

    2 回复  |  直到 7 年前
        1
  •  6
  •   jrok    7 年前

    具有 boost::function_output_iterator :

    #include <vector>
    #include <algorithm>
    #include <boost/function_output_iterator.hpp>
    
    int main() 
    {
        std::vector<double> xx;
        std::vector<double> yy;
        std::vector<const double*> diff;  // const pointers, or else you
                                          // need a const_cast in lambda
    
        std::set_difference(xx.begin(), xx.end(), yy.begin(), yy.end(),
            boost::make_function_output_iterator(
                [&diff](const double& d) { diff.push_back(&d); }
            )
        );
    }
    
        2
  •  4
  •   Stephen Newell    7 年前

    可能有一些内置的东西可以增强,但下面是我编写自己的迭代器的黑客尝试:

    template <typename T, typename FN>
    struct transform_iterator {
        transform_iterator(T &t, FN fn)
          : _t{t}
          , _fn{std::move(fn)} { }
    
        transform_iterator<T, FN>& operator * () { return *this; }
    
        transform_iterator<T, FN>& operator ++ () { return *this; }
    
        template <typename V>
        transform_iterator<T, FN>& operator = (V const &v) {
            _t.push_back(_fn(v));
            return *this;
        }
    
        T &_t;
        FN _fn;
    };
    

    每当有东西试图分配给迭代器(I)时,这将获取一个函数并执行它 认为 事情就是这样 back_inserter 通常工作)。一个普通的助手函数可以创建迭代器:

    template <typename T, typename FN>
    auto make_transform_iterator(T &t, FN fn) {
        return transform_iterator<T, FN>{t, std::move(fn)};
    };
    

    最后一点 iterator_traits 需要专业化所以 transform_iterator 将使用算法。

    namespace std {
        template <typename T, typename FN>
        struct iterator_traits<transform_iterator<T, FN>> {
            using value_type = typename T::value_type;
        };
    }
    

    需要在中设置更多类型 迭代器\u特征 ,但这对我的测试来说已经足够了;您的里程数会有所不同。

    我的 main 如下所示:

    int main() {
        std::vector<int> xx{1, 2, 3};
        std::vector<int> yy{1, 3, 5};
        std::vector<int> diff;
    
        auto ba = make_transform_iterator(diff, [](auto v) { return v + 10; });
        std::set_difference(std::begin(xx), std::end(xx),
                            std::begin(yy), std::end(yy),
                            ba);
        for(auto const &v: diff) {
            std::cout << v << '\n';
        }
        return 0;
    }
    

    您可以将其扩展为使用泛型输出迭代器,而不仅仅是支持 push_back