2010-01-25 47 views
5

Tôi đang gặp sự cố khi sử dụng trình lặp ngược ngược lại trên các vùng chứa không phải const với gcc. Vâng, chỉ có một số phiên bản của gcc.toán tử so sánh gcc reverse_iterator bị thiếu?

#include <vector> 
#include <iostream> 

using namespace std; 

int main() { 
    const char v0[4] = "abc"; 
    vector<char> v(v0, v0 + 3); 

    // This block works fine 
    vector<char>::const_iterator i; 
    for (i = v.begin(); i != v.end(); ++i) 
     cout << *i; 
    cout << endl; 

    // This block generates compile error with gcc 3.4.4 and gcc 4.0.1 
    vector<char>::const_reverse_iterator r; 
    for (r = v.rbegin(); r != v.rend(); ++r) 
     cout << *r; 
    cout << endl; 

    return 0; 
} 

Chương trình này biên dịch OK và chạy với gcc 4.2.1 (Mac Leopard) và Visual Studio 8 và 9 (Windows) và với gcc 4.1.2 (Linux).

Tuy nhiên, có lỗi biên dịch với gcc 3.4.4 (cygwin) và với gcc 4.0.1 (Mac Snow Leopard).

test.cpp:18: error: no match for 'operator!=' in 'r != std::vector<_Tp, _Alloc>::rend() [with _Tp = char, _Alloc = std::allocator<char>]()' 

Đây có phải là một lỗi trong phiên bản trước của gcc?

Do các vấn đề khác với gcc 4.2.1 trên máy Mac, chúng tôi cần sử dụng gcc 4.0.1 trên máy Mac, vì vậy chỉ cần sử dụng trình biên dịch mới hơn không phải là giải pháp hoàn hảo cho tôi. Vì vậy, tôi đoán tôi cần phải thay đổi cách tôi sử dụng trình lặp ngược. Bất kỳ đề xuất?

+0

Để giải quyết sự cố, tác vụ '! (R == v.rend())' có hoạt động không? Hoặc bạn có thể thử nó với phiên bản không đảo ngược thông qua 'r.base()'. –

+0

Nhiều khả năng là thiếu sót; Tôi nghĩ rằng hỗ trợ đầy đủ cho toàn bộ STL là * vẫn * đang diễn ra, mặc dù rất gần. Trở lại trong những ngày 3.4.4 nó đã phần nào không đầy đủ. – meagar

+0

@gf Rất tiếc, "! (R == v.rend())" không hoạt động. Cả hai toán tử "! =" Và "==" đều bị thiếu. –

Trả lời

10

Đó là một khiếm khuyết trong các tiêu chuẩn hiện hành: http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#280

Sửa: Lập một chút: Vấn đề là, trong các tiêu chuẩn hiện hành:

  • vector::reverse_iterator được quy định như std::reverse_iterator<vector::iterator>, và vector::const_reverse_iteratorstd::reverse_iterator<vector::const_iterator>.
  • Các toán tử quan hệ trên std::reverse_iterator được xác định bằng một tham số mẫu duy nhất, làm cho reverse_iterator<iterator>reverse_iterator<const_iterator> không thể so sánh được.

Trong code của bạn, bạn so sánh một const_reverse_iterator với kết quả của gọi "Rend()" trên một vector không const, mà là một (không const) reverse_iterator.

Trong C++ 0x, hai sự thay đổi liên quan được thực hiện để sửa chữa các vấn đề như thế này:

  • toán tử quan hệ trên reverse_iterator bây giờ mất hai tham số mẫu
  • Container như vector có phương thức bổ sung để explicitely yêu cầu const_iterator : cbegin(), cend(), crbegin() và crend ​​().

Trong trường hợp của bạn, một cách giải quyết sẽ được explicitely yêu cầu const_reverse_iterator cho Rend():

vector<char>::const_reverse_iterator r; 
const vector<char>::const_reverse_iterator crend = v.rend(); 
for (r = v.rbegin(); r != crend; ++r) 
    cout << *r; 
+0

Câu trả lời hay. Nó là một lỗi trong tiêu chuẩn hơn là một lỗi trong gcc. –

+0

@Christopher Bruns: Tôi đoán rằng làm cho crend ​​không-const, như r, sẽ làm cho mọi thứ hoạt động. –

+0

@Eric Malenfant: lấy lại dấu đầu dòng của bạn: Tôi nghĩ const_reverse_iterator được định nghĩa là "reverse_iterator ", không chỉ "const_iterator" –

2

điều ngẫu nhiên tôi sẽ cố gắng:

Cast sự trở lại từ Rend() để một const_reverse_iterator để xem nếu vấn đề là khi so sánh thường xuyên đến một iterator const:

r != static_cast<vector<char>::const_reverse_iterator>(v.rend()) 

Nếu điều đó không' t làm việc, làm thế nào về việc thay đổi r từ một const_reverse_iterator đến một iterator đảo ngược thường xuyên.

Không có đầu mối nếu những công việc này, nhưng đó là những gì tôi muốn thử trong tình huống này.

+0

Dàn diễn viên đó khắc phục sự cố. Nó không đẹp lắm nhưng nó hoạt động. –

1

có thể là một lỗi trong vesion cũ của gcc, nhưng tôi đoán là lỗi trong mã của bạn - bạn đã thất bại trong #include <iterator>. Nó có lẽ chỉ đáng xem xét hơn nếu sửa chữa mà không khắc phục được vấn đề.

Mặt khác, nếu bạn đang sử dụng reverse_iterator như hướng dẫn (tức là cơ thể của vòng lặp là cout << *r;), bạn nên có lẽ chỉ cần sử dụng std::copy:

std::ostream_iterator<char> output(std::cout); 

// frontwards 
std::copy(v.begin(), v.end(), output); 

// backwards 
std::copy(v.rbegin(), v.rend(), output); 

Ngoài ra còn có một copy_backwards, nhưng tôi không tin rằng nó sẽ làm những gì bạn muốn.

Chỉnh sửa: Một khả năng khác cần xem xét: nếu thêm tiêu đề bắt buộc không hoạt động và bạn thực sự cần trình lặp ngược lại, bạn có thể xem xét sử dụng STLPort thay cho thư viện gốc (ít nhất là cho trình biên dịch cũ hơn).

+1

Thêm "#include " không thay đổi hành vi. –

2

Kể từ khi vòng lặp cần phải cùng loại có thể so sánh, và một container không const mang lại các trình lặp không phải là const, tại sao không khai báo và khởi tạo trình lặp cuối cùng một lúc.

for (vector<char>::const_reverse_iterator r = v.rbegin(), end_it = v.rend(); r != end_it; ++r) 
    cout << *r; 

Với trình biên dịch cũ hơn, điều này thậm chí có thể mang lại lợi ích hiệu suất nhỏ.

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