2010-02-15 40 views
7

Tôi đang cố gắng để làm một vòng lặp đôi trên một std :: danh sách để hoạt động trên mỗi cặp của các yếu tố. Tuy nhiên, tôi đang gặp một số rắc rối khi khởi tạo trình lặp thứ hai. Mã tôi muốn viết là:Làm thế nào để xây dựng một std :: danh sách iterator trong vòng lặp với gia số

for(std::list<int>::iterator i = l.begin(); i != l.end(); ++i) { 
    for(std::list<int>::iterator j = i+1; j != l.end(); ++j) { 
     ... 
    } 
} 

Điều đó không hiệu quả vì danh sách vòng lặp không truy cập ngẫu nhiên, vì vậy bạn không thể +1. Nhưng tôi đang gặp khó khăn khi tìm một giải pháp thay thế gọn gàng; trình biên dịch dường như không hài lòng với std::list<int>::iterator j(i)++; mà tôi đã có một số hy vọng. Đạt được những gì tôi muốn có vẻ như tôi sẽ phải có một số tăng thêm khó xử mà sẽ không phù hợp với cấu trúc của vòng lặp độc đáo.

Có các lựa chọn thay thế rõ ràng (sử dụng vectơ chẳng hạn!) Nhưng có vẻ như với tôi rằng cần có một số cách hợp lý để làm điều này mà tôi không thấy lúc này.

Cảm ơn trước sự giúp đỡ nào :)

Trả lời

7

Làm thế nào về:

for (std::list<int>::iterator i = l.begin(); i != l.end(); ++i) { 
    for (std::list<int>::iterator j = i; ++j != l.end();) { 
     // ... 
    } 
} 
4
for(std::list<int>::iterator i = l.begin(); i != l.end(); ++i) { 
    std::list<int>::iterator j = i; ++j; 
    for(; j != l.end(); ++j) { 
     ... 
    } 
} 

Trở lại trong trò chơi!

Thực ra, đây là một thành ngữ khá phổ biến trong thuật toán số, vì vậy tôi không thấy nó là xấu xí.

9
for(std::list<int>::iterator i = l.begin(); i != l.end(); ++i) { 
    std::list<int>::iterator j = i; 
    for(std::advance(j, 1); j != l.end(); ++j) { 
     ... 
    } 
} 
+0

'trước' không có giá trị trả lại, nó sửa đổi đối số đầu tiên. (Mà cá nhân tôi không thích.) Điều đó nói rằng, thật dễ dàng để viết một hàm 'advance_copy'. – GManNickG

+0

@GMan: Đã sửa lỗi. Ty! – dirkgently

+0

Không sao cả. Tôi quyết định đi với ý tưởng của tôi như là một câu trả lời thay thế. – GManNickG

2

tôi chỉ cần đi ra khỏi ý tưởng tôi đã có trong câu trả lời dirkgently của:

template <typename Iter, typename Dist> 
Iter advance_copy(Iter pIter, const Dist& pOffset) 
{ 
    std::advance(pIter, pOffset); 

    return pIter; 
} 

// ... 

typedef std::list<int> int_list; 

for(int_list::iterator i = l.begin(); i != l.end(); ++i) 
{ 
    for(int_list::iterator j = advance_copy(i, 1); j != l.end(); ++j) 
    { 
    } 
} 

Bạn có thể thực hiện một lớp các hàm tiện ích quá, để giúp làm cho nó ngắn gọn:

// for consistency, 
template <typename Iter> 
void increment(Iter& pIter) 
{ 
    ++pIter; 
} 

template <typename Iter> 
Iter increment_copy(Iter pIter) 
{ 
    return ++pIter; 
} 

// ... 

typedef std::list<int> int_list; 

for(int_list::iterator i = l.begin(); i != l.end(); ++i) 
{ 
    for(int_list::iterator j = increment_copy(i); j != l.end(); ++j) 
    { 
    } 
} 
1

Tôi sẽ đi cho r Đề xuất của Sean, ngoại trừ việc đưa ra đề xuất của bạn:

for (std::list<int>::iterator i = l.begin(); i != l.end(); ++i) { 
    std::list<int>::iterator j(i); 
    while(++j != l.end()) { 
     // ... 
    } 
} 
0

Nếu bạn đang sử dụng Boost, cách tiếp cận dễ nhất là sử dụng boost::next.

for(std::list<int>::iterator i = l.begin(); i != l.end(); ++i) 
    for(std::list<int>::iterator j = boost::next(i); j != l.end(); ++j) 
+0

Bạn có nghĩa là Boost đã đánh cắp ý tưởng của tôi. :( – GManNickG

2

Các đơn giản "gọn gàng" thay thế có thể được dựa trên thực tế rằng danh sách iterator là một đối tượng kiểu người dùng định nghĩa với các nhà khai thác quá tải (như trái ngược với một built-in type). (Tất nhiên, đây không phải là chính thức đảm bảo, nhưng người ta có thể mong đợi điều này dựa trên bản chất của container danh sách.) Vì lý do này, nó có thể áp dụng tiền tố quá tải ++ nhà điều hành đến một đối tượng tạm thời của loại danh sách iterator.

Để đạt được những gì bạn muốn, bạn chỉ cần tạo một bản sao tạm thời của i, tăng nó bằng cách sử dụng tiền tố ++ và sau đó sử dụng các giá trị kết quả để khởi j

for(std::list<int>::iterator i = l.begin(); i != l.end(); ++i) { 
    for(std::list<int>::iterator j = ++std::list<int>::iterator(i); j != l.end(); ++j) { 
    ... 
    } 
} 

Và đó là nó. Lưu ý rằng mẹo này khá phổ biến và có thể gặp phải trong mã thực theo thời gian. Cũng lưu ý rằng, nó thường sẽ không hoạt động với std::vector vì nhiều triển khai sử dụng các con trỏ dựng sẵn thông thường như các trình lặp vector, nhưng nó thường sẽ làm việc với std::list.

Tuy nhiên, cá nhân, tôi sẽ không thực sự sử dụng mã này trong mã của mình.Bạn đã nhận được một số câu trả lời hay bằng cách thêm một dòng mã bổ sung.

Các vấn đề liên quan