2010-12-10 181 views
11

嗯,我知道为什么,这是因为没有转换,但为什么没有转换?为什么可以将转发迭代器转向反向迭代器,而不是相反呢?更重要的是,如果我想这样做,我该怎么办?是否有一些适配器允许您使用前向迭代器向后迭代?为什么我不能将逆向迭代器转换为向前迭代器?

std::vector<int> buffer(10); 
std::vector<int>::iterator forward = buffer.begin(); 
std::vector<int>::reverse_iterator backward = buffer.rbegin(); 
++forward; 
++backward; 
std::vector<int>::iterator forwardFromBackward = std::vector<int>::iterator(backward); // error! Can't convert from reverse_iterator to iterator! 
std::vector<int>::reverse_iterator backwardFromForward = std::vector<int>::reverse_iterator(forward); // this is fine 
+14

有一个转换:'backward.base();' – ybungalobill 2010-12-10 10:42:00

+0

我敢肯定,你可以使用'reverse_iterator的'在需要时通过迭代器类型作为模板参数传递,无论你使用'iterator'。它不能解决你的问题吗? – Grozz 2010-12-10 10:45:30

+1

你是绝对正确的ybungalobill;我的实际代码比这更复杂一点,我尝试了base(),但它给了我错误,所以我放弃了它,我的大脑抹去了我对它的了解。谢谢!如果您将确切的文本添加为​​答案,我会接受它,因为它真的*是一个答案。 – 2010-12-10 11:00:01

回答

15

你可以写一个辅助函数。 reverse_iterator的一个特殊性是base()给出了一个前向迭代器,该迭代器接下来是反向迭代器解引用的值。 This is because a reverse iterator physically points to the element after the one it logically points to。因此,要将forward迭代器设置为与reverse_iterator相同的项目,您需要将base()的结果递减1,您可以递增反向迭代器第一个,然后取.base()

两个实例如下所示:

#include <iostream> 
#include <vector> 
#include <iterator> 

//result is undefined if passed container.rend() 
template <class ReverseIterator> 
typename ReverseIterator::iterator_type make_forward(ReverseIterator rit) 
{ 
    return --(rit.base()); // move result of .base() back by one. 
    // alternatively 
    // return (++rit).base() ; 
    // or 
    // return (rit+1).base(). 
} 

int main() 
{ 
    std::vector<int> vec(1, 1); 
    std::vector<int>::reverse_iterator rit = vec.rbegin(); 
    std::vector<int>::iterator fit = make_forward(rit); 
    std::cout << *fit << ' ' << *rit << '\n'; 
} 

警告:这种行为是不同于reverse_iterator(iterator)构造的不同。

+0

可能make_forward()应该专门用于指针。 – Abyx 2010-12-10 11:50:15

+0

看起来像ybungalobill不想代表,所以作为第一个答案提到base()你赢了:)谢谢! – 2010-12-10 12:00:03

+0

@Abyx:是的,因为你不能减少从'rit.base()'返回的临时指针,所以最好先创建一个名为'iterator_type'的变量。不过,不需要专业化。 – visitor 2010-12-10 13:39:10

0

您可以使用此代码

container.begin() + (reverseIter - container.rbegin() - 1); 
+0

_Why_。在一个大的列表中,你需要大量的过度遍历,而且这比简单的'(reverseIter + 1).base()' – bobobobo 2013-12-10 20:10:32

+0

什么列表?它是一个*矢量*。 – Abyx 2013-12-11 12:06:27

+0

如果你使用迭代器(而不是简单的整数索引),我假设你这样做的原因是能够将这个公式应用到任何使用迭代器的'std :: container'。 'std :: list'遍历比'std :: vector'更加昂贵,所以你在遍历时只需要1个元素。 – bobobobo 2013-12-11 19:22:23

1

这是很常见的有两种(反向)迭代跨越范围值(如begin(),end()rbegin(),rend())的前插从反向迭代的迭代器。对于由两个反向迭代器rA,rB描述的任何范围,范围rB.base(),rA.base()将在正向方向上跨越相同的范围。

#include <iostream> 
#include <iterator> 
#include <vector> 

int main() { 
    std::vector<int> vec{10,11,12,13,14,15}; 

    // spans the range from 13 to 10 
    auto rfirst=std::rbegin(vec)+2; 
    auto rlast=std::rend(vec); 

    // Loops forward, prints 10 11 12 13 
    for(auto it = rlast.base(); it != rfirst.base(); ++it){ 
    std::cout << *it << " "; 
    } 
} 

如果概念你只在一个单一的项目(如find_if结果)感兴趣,然后通过@visitor使用make_forward。即使在这种情况下,范围想法有助于保持反向迭代的有效性的跟踪:

#include <iostream> 
#include <iterator> 
#include <vector> 
#include <algorithm> 

int main() { 
    std::vector<int> vec{10,11,12,13,14,15}; 

    auto rfirst=std::rbegin(vec); 
    auto rlast=std::rend(vec); 

    auto rfound = std::find_if(rfirst,rlast, [](int v){ return v<13; }); 

    if(rfound != rlast){ 
    std::cout << *rfound << " "; // prints 12 
    auto forwardFound = make_forward(rfound) ; 
    std::cout << *forwardFound << " "; // prints 12 
    } 
}