Tại sao std :: hoán đổi hoạt động trên các phần tử vectơ <bool> trong Clang / Win?


14

Tôi có mã như thế này:

#include <vector>
#include <utility>

int main()
{
   std::vector<bool> vb{true, false};
   std::swap(vb[0], vb[1]);
}

Tranh cãi về sự tỉnh táo của vector<bool>một bên, điều này đã làm việc tốt trên:

  • Clang cho Mac
  • Visual Studio cho Windows
  • GCC cho Linux

Sau đó, tôi đã thử xây dựng nó với Clang trên Windows và nhận được lỗi sau (rút gọn):

error: no matching function for call to 'swap'
                                std::swap(vb[0], vb[1]);
                                ^~~~~~~~~

note: candidate function [with _Ty = std::_Vb_reference<std::_Wrap_alloc<std::allocator<unsigned int> > >, $1 = void] not viable: expects an l-value for 1st argument
inline void swap(_Ty& _Left, _Ty& _Right) _NOEXCEPT_COND(is_nothrow_move_constructible_v<_Ty>&&

Tôi ngạc nhiên rằng kết quả khác nhau giữa các lần thực hiện.

Tại sao nó không hoạt động với Clang trên Windows?


Vì vậy, tôi đoán sự làm rõ cần thiết là: Là kết quả của operator[]một giá trị? và có thể std::swaphoạt động trên giá trị và xvalues?
Mgetz

@Mgetz Vâng. Không theo thứ tự đó. Câu hỏi này đã được hỏi "thật" vào ngày khác và tôi nghĩ rằng câu trả lời đủ thú vị là câu trả lời là "Clang / Win không bị hỏng; mã này đã bị hỏng trong suốt thời gian này nhưng các combo công cụ chính thống không bao giờ bận tâm để nói với bạn "Để viết nó lên đây: P
Các cuộc đua nhẹ nhàng trong quỹ đạo

2
Giống như một FYI, điều này không được biên dịch trong VS 2019 với /permissive-(sự phù hợp), thường được sử dụng theo cách nào đó;)
ChrisMM

1
@ChrisMM Thật vậy! Chế độ phù hợp tắt là một phần của câu đố. (Mặc dù chúng tôi không biết điều đó trước khi xem xét nó!) Và câu trả lời của tôi đã chỉ ra rằng: P
Các cuộc đua Ánh sáng trong Quỹ đạo

Câu trả lời:


15

Tiêu chuẩn không yêu cầu điều này để biên dịch trên bất kỳ chuỗi công cụ nào !

Đầu tiên nhớ lại đó vector<bool>là lạ và đăng ký nó cung cấp cho bạn một đối tượng tạm thời của một loại proxy được gọi std::vector<bool>::reference, chứ không phải là một thực tế bool&.

Thông báo lỗi cho bạn biết rằng nó không thể liên kết tạm thời với consttham chiếu không có giá trị trong template <typename T> std::swap(T& lhs, T& rhs)triển khai chung .

Phần mở rộng!

Tuy nhiên, hóa ra libstdc ++ định nghĩa quá tải cho std::swap(std::vector<bool>::reference, std::vector<bool>::reference), nhưng đây là một phần mở rộng cho tiêu chuẩn (hoặc, nếu nó ở trong đó, tôi không thể tìm thấy bất kỳ bằng chứng nào cho nó).

libc ++ thực hiện điều này quá .

Tôi đoán rằng việc triển khai stdlib của Visual Studio, mà bạn vẫn đang sử dụng, không , nhưng sau đó để thêm sự xúc phạm đến thương tích, bạn có thể liên kết tạm thời với các tham chiếu giá trị trong VS (trừ khi bạn đang sử dụng chế độ tuân thủ), vì vậy std::swapHàm "chung" tiêu chuẩn hoạt động cho đến khi bạn thay thế trình biên dịch VS cho trình biên dịch Clang chặt chẽ hơn.

Do đó, bạn đã dựa vào các tiện ích mở rộng trên cả ba công cụ mà nó hoạt động cho bạn và kết hợp Clang trên Windows là công cụ duy nhất thực sự thể hiện sự tuân thủ nghiêm ngặt.

(Theo tôi, ba bộ công cụ đó đã chẩn đoán điều này nên bạn đã không gửi mã không di động trong suốt thời gian này. 😊)

Gì bây giờ?

Có thể bạn muốn thêm chuyên môn của riêng mình std::swapstd::vector<bool>::reference, nhưng bạn không được phép làm điều này cho các loại tiêu chuẩn; thật vậy, nó sẽ mâu thuẫn với sự quá tải mà libstdc ++ và libc ++ đã chọn để thêm làm tiện ích mở rộng.

Vì vậy, để có thể di động và tuân thủ, bạn nên thay đổi mã của mình .

Có lẽ là một lỗi thời:

const bool temp = vb[0];
vb[0] = vb[1];
vb[1] = temp;

Hoặc sử dụng hàm thành viên tĩnh đặc biệt thực hiện chính xác những gì bạn muốn :

std::vector<bool>::swap(vb[0], vb[1]);

Cũng có thể đánh vần như sau:

vb.swap(vb[0], vb[1]);

Về nhưng không nên cho AFAIK họ được phép làm như vậy. Miễn là họ không phá vỡ mã tuân thủ, họ có thể mở rộng việc triển khai để tạo mã bị hỏng "OK".
NathanOliver

@ NathanOliver-RebstateMonica Vâng, được thôi. Mặc dù vậy, ít nhất họ phải chẩn đoán việc sử dụng những thứ đó? eel.is/c++draft/intro.compliance#8
Các cuộc đua ánh sáng trong quỹ đạo

@LightnessRaceswithMonica có ngôn ngữ nào cấm phần mở rộng này không?
Mgetz

@Mgetz Xin lỗi, tôi không nói được bằng tất cả các ngôn ngữ còn tồn tại nên tôi không thể trả lời
Các cuộc đua nhẹ nhàng trong quỹ đạo

Tôi không chắc chắn nếu sử dụng các tiện ích mở rộng không được định dạng theo tài liệu này . Họ đã thêm một quá tải mà std::vector<bool>::referencekhông có gì thực sự là không đúng. Đối với tôi nghe có vẻ như sử dụng một cái gì đó giống như char * foo = "bar";sẽ yêu cầu chẩn đoán vì điều đó không đúng.
NathanOliver
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.