如何将back_inserter与转换相结合,C ++

时间:2018-04-29 19:02:33

标签: c++ boost iterator c++14

如何使用转换包装back_inserter_iterator之类的OutputIterator? 考虑

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。它对于不可复制的可移动类型也不起作用。

我可以使用提升。

2 个答案:

答案 0 :(得分:5)

使用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); }
        )
    );
}

答案 1 :(得分:4)

可能还有一些东西可以用来提升,但是我的hacky尝试编写自己的迭代器:

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;
};

这将采用一个函数并在尝试分配给迭代器时执行它(我认为这就像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;
    };
}

需要在iterator_traits中设置更多类型,但这对我的测试来说已经足够了;你的里程会有所不同。

我的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的类型。