【问题标题】:How to implement a range adaptor with boost::joined_range如何使用 boost::joined_range 实现范围适配器
【发布时间】:2012-07-24 21:41:10
【问题描述】:

这是一个基于Implement a Range Adaptor with arguments 的范围适配器示例:

#include <boost/range/join.hpp>
#include <boost/range/algorithm.hpp>
#include <boost/range/adaptors.hpp>
#include <boost/range/iterator_range.hpp>
#include <boost/iterator/permutation_iterator.hpp>
#include <vector>
#include <list>
#include <iterator>
#include <iostream>

template <typename Range, typename Index>
class permutation_range :
        public boost::iterator_range<
                boost::permutation_iterator<
                        typename boost::range_iterator<Range>::type,
                        typename boost::range_iterator<Index>::type>>
{
    using value_type = typename boost::range_value<Range>::type;
    using replaced_iterator = boost::permutation_iterator<
                            typename boost::range_iterator<Range>::type,
                            typename boost::range_iterator<Index>::type>;
    using base_t = boost::iterator_range<replaced_iterator>;
public:
    permutation_range(Range& r, Index& i)
            : base_t(replaced_iterator(boost::begin(r), boost::begin(i)),
                    replaced_iterator(boost::end(r), boost::end(i)))
    {}
};

template <typename Range, typename Index>
permutation_range<Range, Index>
permutation(Range& r, Index& i)
{
    return permutation_range<Range, Index>(r, i);
}

int main()
{
    std::vector<int> v1{99, 1, 99,  2, 99, 3};
    std::list<int> indexer{1, 3, 5};
    boost::copy(permutation(v1, indexer),
                std::ostream_iterator<int>(std::cout, " "));
}

输出

1 2 3

我想修改以上内容以使用boost::joined_range。换句话说,取两个向量,然后将它们连接到permutation_range 内的一个更长的范围内。这个想法很简单:

示例将输出2 4 6

int main()
{
    std::vector<int> v1{1, 2, 3};
    std::vector<int> v2{4, 5, 6};
    std::list<int> indexer{1, 3, 5};
    boost::copy(permutation(v1, v2, indexer),
                std::ostream_iterator<int>(std::cout, " "));
}

到目前为止,我所有的尝试都以一大堆编译器错误告终,我没有展示这些尝试,因为我可能会走得很远。我不知道这是否可能,但是有人可以在这里帮助我吗?

FINAL EDIT(在基类之前初始化范围的解决方案)

#include <boost/range/join.hpp>
#include <boost/range/algorithm.hpp>
#include <boost/range/adaptors.hpp>
#include <boost/range/iterator_range.hpp>
#include <boost/iterator/permutation_iterator.hpp>
#include <vector>
#include <list>
#include <iterator>
#include <iostream>

template <typename R1, typename R2>
struct initialize_me_first
{
    initialize_me_first(typename boost::range::joined_range<const R1, const R2> j)
    : j_range(j)
    {}
    typename boost::range::joined_range<const R1, const R2> j_range;
};

template <typename Range1, typename Range2, typename Index>
class permutation_range :
        public initialize_me_first<Range1, Range2>,
        public boost::iterator_range<
                boost::permutation_iterator<
                        typename boost::range_iterator<
                            boost::range::joined_range<Range1, Range2>>::type,
                        typename boost::range_iterator<Index>::type>>
{
    using value_type = typename boost::range_value<Range1>::type;
    using replaced_iterator = boost::permutation_iterator<
                    typename boost::range_iterator<
                            boost::range::joined_range<Range1, Range2>>::type,
                            typename boost::range_iterator<Index>::type>;
    using base_t = boost::iterator_range<replaced_iterator>;
    using init = initialize_me_first<Range1, Range2>;
public:
    permutation_range(const Range1& r1, const Range2& r2, const Index& i)
            : init(boost::join(r1, r2)),
              base_t(replaced_iterator(boost::begin(init::j_range),
                                       boost::begin(i)),
                    replaced_iterator(boost::end(init::j_range),
                                       boost::end(i)))
    {}
};

template <typename Range1, typename Range2, typename Index>
permutation_range<const Range1, const Range2, const Index>
permutation(const Range1& r1, const Range2& r2, const Index& i)
{
    return permutation_range<const Range1,
                             const Range2,
                             const Index>(r1, r2, i);
}

int main()
{
    std::vector<int> v1{1, 2, 3};
    std::vector<int> v2{4, 5, 6};
    std::list<int> indexer{1, 3, 5};
    boost::copy(permutation(v1, v2, indexer),
                std::ostream_iterator<int>(std::cout, " "));
}

【问题讨论】:

    标签: c++ boost boost-range


    【解决方案1】:

    要连接两个范围,请使用boost::join

    #include <boost/range/join.hpp>
    
    boost::copy(permutation(boost::join(v1, v2), indexer), ...
    

    但是将您的Range 参数更改为通过常量引用而不是非常量引用传递。没有理由要求这些参数的可修改版本,因为您实际上并没有改变它们的内容。

    【讨论】:

    • 谢谢,我也意识到如果我想保留permutation(v1, v2, indexer) 语法,我可以将boost::join 粘贴在permutation 中。但是,我最初的目标是将permutation_range 更改为使用boost::join(虽然不知道这是否可能)。
    • 那会更难。您的permutation_range 需要拥有它创建的连接范围的副本——它需要为它创建的两个replaced_iterator 对象传递相同的r 值。该范围必须存在于之前基类被初始化。这是可以解决的,但是在参数列表的 middle 中还有一个有效的“可选”参数 (v2) 的附加语法复杂性。如果调用者想要加入范围,让调用者负责,并让你的界面简单并只专注于一件事。
    • 关于界面的好点,非常感谢您的帮助。在您的 cmets 之后,我能够想出一些东西(请参阅有问题的编辑),但是,如何在基类初始化之前获得范围?
    • 我想出了一个通过从两个类继承的解决方案(参见最终编辑)。再次感谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-14
    • 2012-04-15
    • 1970-01-01
    • 1970-01-01
    • 2011-09-07
    相关资源
    最近更新 更多