Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/162.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ boost::Adapters::transformed后跟boost::Adapters::filtered调用函数两次_C++_Boost_Functional Programming_Boost Range - Fatal编程技术网

C++ boost::Adapters::transformed后跟boost::Adapters::filtered调用函数两次

C++ boost::Adapters::transformed后跟boost::Adapters::filtered调用函数两次,c++,boost,functional-programming,boost-range,C++,Boost,Functional Programming,Boost Range,我试图将一个boost::adapters::transformed(我们称之为map)链接到一个boost::adapters::filter(我们称之为filter)-这个想法是在一个范围内映射一个fun,它返回一个“可能”(在我的例子中,是一个std::pair)并只输出部分结果。我的第一次实施: define BOOST_RESULT_OF_USE_DECLTYPE // enable lambda arguments for Boost.Range #include <boost

我试图将一个
boost::adapters::transformed
(我们称之为
map
)链接到一个
boost::adapters::filter
(我们称之为
filter
)-这个想法是在一个范围内映射一个
fun
,它返回一个“可能”(在我的例子中,是一个
std::pair
)并只输出部分结果。我的第一次实施:

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;
}
每次
谓词
true
fun
被调用两次。这是预期的行为吗?我是做错了什么,还是这是Boost中的一个bug(我使用的是1.48)


编辑:我在Boost的主干版本上尝试了这个方法,但它仍然会发生。

第一次调用它时,它被传递到您的过滤器-在增量过程中

第二次在您的范围内调用时,基于-在取消引用期间。它不会缓存结果

即,刚刚通过范围:

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

检查的实现(过滤基于此)。它不做任何缓存

如果改造成本很高怎么办

过滤后的数据不使用其输入来源的knowladge

缓存结果需要增加过滤迭代器的大小。想想缓存的结果应该存储在哪里。它应该被复制到过滤迭代器的某个成员中

所以,基本上,在缓存空间和解引用计数之间存在权衡


编辑:我已经证明了cached_迭代器的概念,该迭代器缓存解引用的结果,并在每次前进时使其无效。另外,我还制作了相应的量程适配器

以下是它的使用方法:

auto s = v | transformed(only_even) | cached | reversed | cached | flt | flt | flt | flt | flt | flt;
您应该将缓存的放在要缓存结果的链中


是的,我在看了代码后才知道。这对
transformed
,调用
fun
两次有意义吗?考虑其他语言(Python、Haskell等,这毫无意义)。如果转换很昂贵怎么办?在这种情况下,您可以使用“缓存”适配器,如答案所示。
fun: 1
fun: 2
fun: 3
fun: 4
fun: 5
fun: 6
fun: 7
fun: 8
fun: 9
fun: 10
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