2013-09-01 63 views
7

Trong C++ 11, sử dụng lambda/for_each, làm thế nào để chúng ta lặp một mảng từ đầu?Trong C++, làm thế nào để lặp lại mảng ngược lại bằng cách sử dụng for_each?

Tôi đã thử các sau đây, nhưng cả hai kết quả trong vòng lặp vô hạn:

for_each (end(A), begin(A), [](int i) { 
    .... 
}); 

for_each (A.rend(), A.rbegin(), [](int i) { 
    ... 
}); 

Bất kỳ ý tưởng? Cảm ơn.

+2

Bạn đảo ngược Rend và rbegin. – Borgleader

+0

@Borgleader Có, bạn đã đúng. Cảm ơn. – user350954

Trả lời

18

Bạn đã bỏ lỡ điều này?

Lật rbegin & rend

for_each (A.rbegin(), A.rend(), [](int i) { 
    ... 
}); 

Tăng iterator ngược của bạn di chuyển chúng về phía đầu của container

+0

Rất tiếc, lỗi của tôi! Cảm ơn rất nhiều! – user350954

5

std::for_each(A.rbegin(), A.rend(), [](int i) { /*code*/ }); sự là giải pháp đơn giản.

tôi thay vì đã viết backwards mà phải mất một chuỗi, chiết xuất các beginend iterator từ nó bằng cách sử dụng miễn phí beginend chức năng (với std::beginstd::endusing tờ khai lân cận - đầy đủ ADL), tạo ra vòng lặp ngược xung quanh họ, sau đó trả về một chuỗi với hai trình lặp ngược này.

Nó là loại gọn gàng, bởi vì bạn sẽ có được cú pháp sau:

for(int i : backwards(A)) { 
    // code 
} 

mà tôi tìm thấy dễ dàng hơn để đọc hơn std::for_each hoặc bằng tay for vòng.

Nhưng tôi hơi điên.

Dưới đây là số tối thiểu backwards. Một giải pháp đầy đủ về xử lý adl và một vài trường hợp góc tốt hơn.

template<class It, class C> 
struct range_for_t{ 
    It b,e; 
    C c; // for lifetime 
    It begin()const{return b;} 
    It end()const{return e;} 
} 
template<class It, class C> 
range_for_t<It,C> range_for(It b,It e,C&& c){ 
    return {std::move(b),std::move(e),std::forward<C>(c)}; 
} 

template<class It> 
range_for_t<It,int> range_for(It b,It e){ 
    return {std::move(b),std::move(e)}; 
} 

Phạm vi đơn giản cho phạm vi chỉ. Có thể được tăng cường với chuyển tiếp hoàn hảo.

Chuyển C làm vùng chứa có thể cần kéo dài suốt đời. Nếu được thông qua như rvalue, sao chép được thực hiện, nếu không chỉ cần tham khảo. Nó không được sử dụng.

phần tiếp theo là dễ dàng:

template<class It> 
auto reverse_it(It it){ 
    return std::reverse_iterator<It>(std::move(it)); 
} 
template<class C> 
auto backwards(C&&c){ 
    using std::begin; using std::end; 
    auto b=begin(c), e=end(c); 
    return range_for(
    reverse_it(e),reverse_it(b), 
    std::forward<C>(c) 
); 
} 

Đó là chưa được kiểm tra nhưng nên làm việc.

Một thử nghiệm quan trọng là đảm bảo nó hoạt động khi bạn ăn một vec rvalue như:

for(auto x:backwards(make_vec())) 

công trình - đó là những gì mà lộn xộn xung quanh lưu trữ C là về. Nó cũng giả định rằng các trình vòng lặp container được chuyển đổi có các trình vòng lặp hoạt động độc đáo.

+0

Bạn có thể chia sẻ mã của hàm 'ngược lại '... – Hashken

+0

@hash sketch được thêm vào hay không. – Yakk

0

Boost cung cấp một tính năng có tên reversed, mà có thể được sử dụng với C++ 11 range based for loop như mô tả Yakk trong câu trả lời của mình:

for(int i : reverse(A)) 
{ 
    // code 
} 

hoặc

for(int i : A | reversed) 
{ 
    // code 
}