2011-08-05 46 views

回答

63

使用旧for环路:

for (auto it = values.begin(); it != values.end(); ++it) 
{ 
     auto & value = *it; 
     //... 
} 

有了这个,你已经value以及迭代it。使用任何你想使用的。


编辑:

虽然我不建议,但如果你想使用基于范围的for环路(是的,无论出于何种原因:d),那么你可以这样做:

auto it = std::begin(values); //std::begin is a free function in C++11 
for (auto& value : values) 
{ 
    //Use value or it - whatever you need! 
    //... 
    ++it; //at the end OR make sure you do this in each iteration 
} 

此方法可避免搜索给出value,因为valueit始终保持同步。

+0

是啊,这就是我我只是想知道是否有基于范围的循环的解决方案 –

+0

@小太郎:查看编辑 – Nawaz

+4

我同意旧的for循环的第一个解决方案好得多:P –

3

范围基于for循环作为在Java中的C++对口foreach允许阵列元件容易迭代创建。它是为了消除像迭代器这样的复杂结构的使用,以使其变得简单。我想要一个iterator,正如纳瓦兹所说,你将不得不使用正常的for循环。

+0

我希望他们会提供一个类似的循环,而不是迭代器,尽管:( –

+1

我很高兴,你得到的是他们的价值,而不是迭代器,因为我基于范围'for'是语法糖和减少打字量。取消引用迭代器会使其容易出错,尤其是在使用'auto' – TeaOverflow

13

这是一个代理包装类,允许您通过将其隐藏到自己的变量中来公开隐藏的迭代器。

#include <memory> 
#include <iterator> 

/* Only provides the bare minimum to support range-based for loops. 
    Since the internal iterator of a range-based for is inaccessible, 
    there is no point in more functionality here. */ 
template< typename iter > 
struct range_iterator_reference_wrapper 
    : std::reference_wrapper<iter> { 
    iter &operator++() { return ++ this->get(); } 
    decltype(* std::declval<iter>()) operator*() { return * this->get(); } 
    range_iterator_reference_wrapper(iter &in) 
     : std::reference_wrapper<iter>(in) {} 
    friend bool operator!= (range_iterator_reference_wrapper const &l, 
          range_iterator_reference_wrapper const &r) 
     { return l.get() != r.get(); } 
}; 

namespace unpolluted { 
    /* Cannot call unqualified free functions begin() and end() from 
     within a class with members begin() and end() without this hack. */ 
    template< typename u > 
    auto b(u &c) -> decltype(begin(c)) { return begin(c); } 
    template< typename u > 
    auto e(u &c) -> decltype(end(c)) { return end(c); } 
} 

template< typename iter > 
struct range_proxy { 
    range_proxy(iter &in_first, iter in_last) 
     : first(in_first), last(in_last) {} 

    template< typename T > 
    range_proxy(iter &out_first, T &in_container) 
     : first(out_first), 
     last(unpolluted::e(in_container)) { 
     out_first = unpolluted::b(in_container); 
    } 

    range_iterator_reference_wrapper<iter> begin() const 
     { return first; } 
    range_iterator_reference_wrapper<iter> end() 
     { return last; } 

    iter &first; 
    iter last; 
}; 

template< typename iter > 
range_proxy<iter> visible_range(iter &in_first, iter in_last) 
    { return range_proxy<iter>(in_first, in_last); } 

template< typename iter, typename container > 
range_proxy<iter> visible_range(iter &first, container &in_container) 
    { return range_proxy<iter>(first, in_container); } 

用法:

#include <vector> 
#include <iostream> 
std::vector<int> values{ 1, 3, 9 }; 

int main() { 
    // Either provide one iterator to see it through the whole container... 
    std::vector<int>::iterator i; 
    for (auto &value : visible_range(i, values)) 
     std::cout << "# " << i - values.begin() << " = " << ++ value << '\n'; 

    // ... or two iterators to see the first incremented up to the second. 
    auto j = values.begin(), end = values.end(); 
    for (auto &value : visible_range(j, end)) 
     std::cout << "# " << j - values.begin() << " = " << ++ value << '\n'; 
} 
+1

+1进行封装实验时。:-) – Nawaz

9

我想我就这个问题和找到解决方案。

用法:

for(auto i : ForIterator(some_list)) { 
    // i is the iterator, which was returned by some_list.begin() 
    // might be useful for whatever reason 
} 

The implementation并不难:

template <typename T> struct Iterator { 
    T& list; 
    typedef decltype(list.begin()) I; 

    struct InnerIterator { 
     I i; 
     InnerIterator(I i) : i(i) {} 
     I operator *() { return i; } 
     I operator ++() { return ++i; } 
     bool operator != (const InnerIterator& o) { return i != o.i; } 
    }; 

    Iterator(T& list) : list(list) {} 
    InnerIterator begin() { return InnerIterator(list.begin()); } 
    InnerIterator end() { return InnerIterator(list.end()); } 
}; 
template <typename T> Iterator<T> ForIterator(T& list) { 
    return Iterator<T>(list); 
} 
+1

请*,*使用'ForIterator'的函数模板... – Xeo

+0

啊,嗯,是。我没有完全明白,编译器可以从构造函数中获得他的T ...所以我想到了decltype并且看到了用法膨胀......并且我没有看到它可以从函数中获得他的T ...函数模板,谢谢。是对的,我现在怎么做? – payload

+2

是的,看起来不错。 FWIW,虽然有'boost :: counting_iterator',但确实如此,并且方便地用'boost :: counting_range'包装,所以你可以这样写:for(auto it:boost :: counting_range(r.begin(), r.end()))'。 :) – Xeo

1

有做这std::vector,这也应该工作,如果你是在调整向量的一个非常简单的方法过程(我不确定接受的答案是否考虑这种情况)

如果b是您的矢量,哟你可以做

for(auto &i:b){ 
    auto iter = b.begin() + (&i-&*(b.begin())); 
} 

其中iter将是您所需的迭代器。

这利用了C++ vectors are always contiguous的事实。

+1

如果您已经在利用C++向量连续的事实,那么您也可以利用这样一个事实:任何理智的实现都只是将'vector :: iterator'类型定义为'T *':使用'static_assert() ',那么只需使用'T * iter =&i;'。 – cmaster

0

让我们这样做很脏... 我知道,0x70h与堆栈的使用,编译器版本变化,.... 应该被编译器暴露出来,但它不是:-(

char* uRBP = 0; __asm { mov uRBP, rbp } 
Iterator** __pBegin = (Iterator**)(uRBP+0x70); 
for (auto& oEntry : *this) { 
    if (oEntry == *pVal) return (*__pBegin)->iPos; 
}