2013-07-06 49 views
30

Tôi nhận được cảnh báo ký/unsigned không phù hợp cho đoạn mã sau:Sử dụng auto trong vòng C++

auto n = a.size(); 
for (auto i = 0; i < n; i++) { 
} 

Vấn đề là bằng cách gán 0-i nó trở nên int hơn size_t. Vì vậy, những gì là tốt hơn:

size_t n = a.size(); 
for (size_t i = 0; i < n; i++) { 
} 

hay này:

auto n = a.size(); 
for (size_t i = 0; i < n; i++) { 
} 

hoặc có thể bạn có một giải pháp tốt hơn? Tôi thích cái đầu tiên hơn vì nó phù hợp hơn một chút, nó chỉ sử dụng size_t thay vì cả hai size_tauto cho cùng một mục đích.

+3

how about 'auto i = 0u'? – jalf

+0

Làm thế nào về việc sử dụng một int nếu bạn cần một chỉ số trong vòng lặp của bạn? Sử dụng một chỉ mục unsigned có thể nhận được khó chịu rất nhanh chóng. Ví dụ. 'i

Trả lời

38

Một loạt trụ sở vòng lặp có thể là một giải pháp làm sạch:

for (const auto& i : a) 
{ 

} 

Ở đây, i là một tài liệu tham khảo const đến một yếu tố của container a.

Nếu không, nếu bạn cần chỉ mục hoặc nếu bạn không muốn lặp lại toàn bộ phạm vi, bạn có thể nhận loại với decltype(a.size()).

for (decltype(a.size()) i = 0; i < a.size(); ++i) { 
} 
+4

1 vấn đề với vòng lặp dựa trên phạm vi là chỉ mục không có sẵn – RiaD

+0

Vâng, đó là vấn đề lớn thực sự, tôi không muốn quản lý các chỉ mục một cách riêng biệt. – user2381422

+0

Cảm ơn bạn vì điều này. Tôi không biết C++ 11 giới thiệu vòng lặp dựa trên phạm vi. – stepanbujnak

18

Tùy thuộc vào những gì bạn muốn làm bên trong vòng lặp và khả năng của trình biên dịch, phạm vi dựa trên vòng lặp có thể là giải pháp tốt hơn.

Tất cả các giải pháp được trình bày của bạn không phải là xấu trong hầu hết các trường hợp, với sự khác biệt nhỏ Giải pháp đầu tiên của bạn thực sự là lựa chọn tồi tệ hơn và đó chính xác là những gì trình biên dịch cho bạn biết. giải pháp thứ hai là tốt hơn nhưng nếu bạn muốn tránh trực tiếp xác định loại vì đơn giản hoặc một số thay đổi trong tương lai, bạn có thể làm như sau:

auto n = a.size(); 
for (decltype(n) i = 0; i < n; i++) { 
} 

Bằng cách này bạn ràng buộc in loại để luôn phù hợp với nhau.

5

Nếu bạn sử dụng đúng chữ, bạn sẽ ổn: 0U. tự động thấy một chữ loại int, vì vậy đó là loại i. Thêm U và thay vào đó nó sẽ thấy một chữ ký không dấu. Nếu không, bạn muốn sử dụng decltype như những người khác được đề xuất, đặc biệt là vì sizeof (size_t) có thể lớn hơn sizeof (int) (trên Windows, OS X, v.v. nếu chạy ở chế độ dài 64 bit).

+2

'sizeof (0U)' luôn luôn 'sizeof (size_t)' theo tiêu chuẩn? – Flexo

+0

@Flexo: Bài chỉnh sửa để phản ánh điều đó và khuyến khích chấp nhận câu trả lời khác. –

+0

-1. Nửa đầu của câu trả lời này là sai như Flexo nói. Và nửa thứ hai về cơ bản nói "làm như các câu trả lời khác nói". Nếu bạn muốn "khuyến khích chấp nhận câu trả lời khác", bạn có thể xóa câu trả lời này. – interjay

-2
for(auto n = a.size(), i = 0; i != n; ++i) { 
} 

... có lẽ là giải pháp sạch nhất nếu bạn cần truy cập chỉ mục, cũng như yếu tố thực tế.

Cập nhật:

for(auto n = a.size(), i = n*0; i != n; ++i) { 
} 

Sẽ là một cách giải quyết cho Richard Smiths nhận xét, mặc dù nó không giống mà sạch sẽ nữa.

+4

Điều này không chính xác: trong khai báo 'tự động' khai báo nhiều biến,' tự động' được suy ra độc lập cho mỗi biến và mã bị sai hình thành nếu các loại suy luận không giống nhau. –

2

Đối thảo luận:

auto n = a.size(); 
for (auto i = n-n; i<n; ++i) { 
} 

Lưu ý rằng với nhiều loại nhỏ hơn int, kết quả phép trừ mở rộng để int (gọi tắt là chương trình khuyến mãi số nguyên).

1

Đang cố gắng để được const-đúng bất cứ khi nào có thể, tôi thường viết:

const auto n(a.size()); 
for (auto i = decltype(n){0}; i < n; ++i) 
{ 
} 

Nó không phải là rất ngắn gọn, nhưng nó rõ ràng rằng bạn muốn có một biến khởi tạo 0 loại n 's (và nconst).

0

Đây là giải pháp đơn giản & làm sạch.

for(auto i: a) 
{ 
} 
Các vấn đề liên quan