boost ::适配器::转换为boost :: apapters ::过滤呼叫函数两次



我正在尝试将 boost::adaptors::transformed(我们称为 map)链接到 boost::adaptors::filtered(我们称其为 filter) - 这个想法是映射返回"也许"的 fun(in我的情况,a std::pair<bool, T>)在一个范围内,仅输出结果的一部分。我的第一个实现:

define BOOST_RESULT_OF_USE_DECLTYPE // enable lambda arguments for Boost.Range
#include <boost/range/adaptor/filtered.hpp>
#include <boost/range/adaptor/transformed.hpp>
struct OnlyEven
{
    typedef int argument_type;
    typedef std::pair<bool, int> result_type;
    result_type operator()(argument_type x) const
    {
        std::cout << "fun: " << x << std::endl;
        return std::make_pair(x % 2 == 0, x);
    }
} only_even;
int main(int argc, char* argv[])
{
    auto map = boost::adaptors::transformed;
    auto filter = boost::adaptors::filtered;
    int v[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    auto s = v | map(only_even) | filter([](std::pair<bool, int> x)->bool{ return x.first; });
    for (auto i : s) {}
    return 0;
}

当我运行此功能时,我会得到:

fun: 1
fun: 2
fun: 2
fun: 3
fun: 4
fun: 4
fun: 5
fun: 6
fun: 6
fun: 7
fun: 8
fun: 8
fun: 9
fun: 10
fun: 10

每当predicatetrue时,fun被称为两次。这是预期的行为吗?我是做错了什么,还是/这是一个错误的错误(我正在使用1.48)?

edit :我在Boost的中继版本上尝试了此操作。

第一次将其传递给您的过滤器时被调用 -

第二次在您的基于范围的情况下被调用。它不会缓存结果。

即,仅通过范围:

++++++++++boost::begin(s);

给出:

fun: 1
fun: 2
fun: 3
fun: 4
fun: 5
fun: 6
fun: 7
fun: 8
fun: 9
fun: 10

检查Filter_iterator的实现(过滤是基于它)。它没有任何缓存。

如果转换价格昂贵怎么办?

滤波器不使用INTUP来自何处的知识。

结果的缓存将需要递增的过滤迭代器的尺寸。试想一下应存储缓存结果的位置。它应复制到某些过滤的迭代器中。

因此,基本上,缓存的空间和删除的空间之间存在权衡。


编辑:我已经对cached_iterator进行了概念验证,该cached_iterator caches导致退出,并在每个前进的情况下都无效。另外,我制作了相应的范围适配器。

在这里如何使用:

auto s = v | transformed(only_even) | cached | reversed | cached | flt | flt | flt | flt | flt | flt;

您应该在要缓存结果的链条中放置缓存

实时演示

#include <boost/range/adaptor/filtered.hpp>
#include <boost/range/adaptor/transformed.hpp>
#include <boost/range/adaptor/reversed.hpp>
#include <boost/range/adaptor/map.hpp>
#include <boost/range/algorithm.hpp>
#include <iostream>
#include <ostream>
// ____________________________________________________________________________________________ //
#include <boost/iterator/iterator_adaptor.hpp>
#include <boost/range/iterator.hpp>
#include <iterator>
namespace impl
{
template<typename Iterator>
class cached_iterator : public boost::iterator_adaptor<cached_iterator<Iterator>,Iterator>
{
    typedef boost::iterator_adaptor<cached_iterator,Iterator> super;
    mutable bool invalidated;
    mutable typename std::iterator_traits<Iterator>::value_type cached;    
public:
    cached_iterator() : invalidated(true) {}
    cached_iterator(const Iterator &x) : super(x), invalidated(true) {}
    typename std::iterator_traits<Iterator>::value_type dereference() const
    {
        if(invalidated)
        {
            cached = *(this->base());
            invalidated=false;
            return cached;
        }
        else
        {
            return cached;
        }
    }
    void increment()
    {
        invalidated=true;
        ++(this->base_reference());
    }
    void decrement()
    {
        invalidated=true;
        --(this->base_reference());
    }
    void advance(typename super::difference_type n)
    {
        invalidated=true;
        (this->base_reference())+=n;
    }
};
template<typename Iterator> cached_iterator<Iterator> make_cached_iterator(Iterator it)
{
    return cached_iterator<Iterator>(it);
}
template< class R >
struct cached_range : public boost::iterator_range<cached_iterator<typename boost::range_iterator<R>::type> >
{
private:
    typedef boost::iterator_range<cached_iterator<typename boost::range_iterator<R>::type> > base;
public:
    typedef R source_range_type;
    cached_range( R& r )
        : base( make_cached_iterator(boost::begin(r)), make_cached_iterator(boost::end(r)) )
    { }
};
template<typename InputRange>
inline cached_range<const InputRange> cache(const InputRange& rng)
{
    return cached_range<const InputRange>(rng);
}
template<typename InputRange>
inline cached_range<InputRange> cache(InputRange& rng)
{
    return cached_range<InputRange>(rng);
}
struct cache_forwarder{};
cache_forwarder cached;
template< class InputRange >
inline cached_range<const InputRange>
operator|( const InputRange& r, cache_forwarder )
{
    return cache(r);
}
template< class InputRange >
inline cached_range<InputRange>
operator|( InputRange& r, cache_forwarder )
{
    return cache(r);
}
} // namespace impl
// ____________________________________________________________________________________________ //

struct OnlyEven
{
    typedef int argument_type;
    typedef std::pair<bool, int> result_type;
    result_type operator()(argument_type x) const
    {
        std::cout << "fun: " << x << std::endl;
        return std::make_pair(x % 2 == 0, x);
    }
} only_even;
int main()
{
    using namespace impl;
    using namespace boost::adaptors;
    using namespace std;
    int v[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    auto flt =  filtered([](std::pair<bool, int> x)->bool{ return x.first; });
    auto s = v | transformed(only_even) | cached | reversed | cached | flt | flt | flt | flt | flt | flt;
    boost::copy(s | map_values, ostream_iterator<int>(cout,"n") );
    return 0;
}

输出是:

fun: 10
10
fun: 9
fun: 8
8
fun: 7
fun: 6
6
fun: 5
fun: 4
4
fun: 3
fun: 2
2
fun: 1

最新更新