调整自定义迭代器,以便(a?)reverse_iterator可以翻转它的输出

时间:2014-05-22 17:56:10

标签: c++ iterator

最近,用户@Mooing Duck设计了concatenated_range,这是一个优雅的自定义迭代器,可以解决链接问题'两个迭代器,都在引擎盖下。

它的用途很有用:

auto range0=concatenate_ranges(x,x+i-1,x+i,x+a5+1);
a6=foo(range0.first,range0.second); 

现在,我想通过做(示例#2)来适应它:

auto range0=concatenate_ranges(x+a5+1,x+i-1,x+i+1,x+n);
a6=foo(std::reverse_iterator<float*>(range0.second),std::reverse_iterator<float*>(range0.first));

毋庸置疑,编译器并不高兴。另一种选择(不确定订购是否正确):

auto range0=concatenate_ranges(std::reverse_iterator<float*>(x+n),x+i+1,x+i-1,std::reverse_iterator<float*>(x+a5[i]+1));
a6=foo(range0.first,range0.second);

不是理所当然的:(。

我的问题是:我如何调整concatenate_ranges()以便它的输出可以 馈入std::reverse_iterator(如上面的第二个例子)。另外,我不介意 使用boost::如果它让事情变得更容易。

编辑:

用户@Jack报告原始答案中的链接没有显示他的代码。我不知道这个问题有多广泛,所以为了清楚起见,我重现了我在这里提到的代码(请参阅原始答案的解释):

#include <boost/iterator/iterator_facade.hpp>
#include <iterator>
#include <cassert>

template<class base>
class concatenated_range_iterator 
    : public boost::iterator_facade<
        concatenated_range_iterator<base>,
        typename std::iterator_traits<base>::value_type,
        typename std::iterator_traits<base>::iterator_category,
        typename std::iterator_traits<base>::reference,
        typename std::iterator_traits<base>::difference_type
        >
{
public:
    typedef typename std::iterator_traits<base>::iterator_category iterator_category;
    typedef typename std::iterator_traits<base>::value_type        value_type;
    typedef typename std::iterator_traits<base>::difference_type   difference_type;
    typedef typename std::iterator_traits<base>::pointer           pointer;
    typedef typename std::iterator_traits<base>::reference         reference;

    concatenated_range_iterator() = default;
    concatenated_range_iterator(bool begin, base begin1, base end1, base begin2, base end2) 
        :current(begin?begin1:end2), end_first(end1), begin_second(begin2), in_first(begin)
        {}

    reference dereference() {return *current;}
    reference dereference() const {return *current;}
    bool equal(const concatenated_range_iterator& rhs) const {
        assert(end_first==rhs.end_first);
        assert(begin_second==rhs.begin_second);
        return in_first==rhs.in_first && current==rhs.current;
    }
    void increment() {
        ++current;
        if (in_first) {
            if (current==end_first) {
                current = begin_second;
                in_first = false;
            }
        } 
    }
    void decrement() {
        if (!in_first) {
            if (current==begin_second) {
                current = end_first;
                in_first = true;
            }
        }
        --current;
    }
    void advance(difference_type n) {
        if (n>=0) {
            if (in_first) {
                difference_type safe = end_first-current;
                if (safe <= n) {
                    current = begin_second;
                    n -= safe;
                    in_first = false;
                }
            }
        } else {
            if (!in_first) {
                difference_type safe = current-begin_second;
                if (safe <= n) {
                    current = end_first;
                    n += safe;
                    in_first = true;
                }
            }
        }
        current += n;
    }
    difference_type distance_to(const concatenated_range_iterator& rhs) const {
        assert(end_first==rhs.end_first);
        assert(begin_second==rhs.begin_second);
        if (in_first) {
            if (rhs.in_first) 
                return rhs.current-current;
            else
                return rhs.current-begin_second + end_first-current;
        } else {
            if (rhs.in_first) 
                return rhs.current-end_first + begin_second-current;
            else
                return rhs.current-current;
        }
    }
protected:
    base current; 
    base end_first;
    base begin_second;
    bool in_first;
};
template<class base>
std::pair<concatenated_range_iterator<base>,concatenated_range_iterator<base>>
    concatenate_ranges(base first1, base end1, base first2, base end2)
{
    return std::pair<concatenated_range_iterator<base>,concatenated_range_iterator<base>>(
        concatenated_range_iterator<base>(true, first1, end1, first2, end2),
        concatenated_range_iterator<base>(false, first1, end1, first2, end2)
        );
}


#include <vector>
#include <iostream>
int main() {
    std::vector<int> vars = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};

    auto range = concatenate_ranges(vars.begin(), vars.begin()+4, vars.begin()+5, vars.end());
    for(auto iter=range.first; iter!=range.second; ++iter)
        std::cout << *iter << ' ';
}

1 个答案:

答案 0 :(得分:5)

您正在错误地实例化reverse_iterator模板。尝试

auto fst = std::reverse_iterator<decltype(range0.second)>(range0.second);
auto snd = std::reverse_iterator<decltype(range0.first)>(range0.first);

使类型更明确:

typedef std::vector<int>::iterator VI;
typedef concatenated_range_iterator<VI> CRVI;
typedef std::pair<CRVI, CRVI> CRVIrange;
CRVIrange range0 = concatenate_ranges(vars.begin(), vars.begin()+2,
                                       vars.begin()+5, vars.end());

typedef std::reverse_iterator<CRVI> RCRVI;
RCRVI fst = RCRVI(range0.second);
RCRVI snd = RCRVI(range0.first);

我不想写下像std::pair<std::reverse_iterator<concatenated_range_iterator<std::vector<int>::iterator>>,std::reverse_iterator<concatenated_range_iterator<std::vector<int>::iterator>>>

这样的内容