Clang / Win의 vector <bool> 요소에서 std :: swap이 작동하지 않는 이유는 무엇입니까?


14

다음과 같은 코드가 있습니다.

#include <vector>
#include <utility>

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

vector<bool>제쳐두고 의 정신에 대한 논쟁 , 이것은 잘 작동했습니다 :

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

그런 다음 Windows에서 Clang을 사용하여 빌드하려고 시도하고 다음과 같은 오류가 발생했습니다.

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>&&

구현마다 결과가 다르다는 것에 놀랐습니다.

Windows에서 Clang과 함께 작동하지 않는 이유는 무엇입니까?


그래서 나는 설명이 필요하다고 생각합니다 : operator[]lvalue 의 결과 입니까? std::swaprvalue 및 xvalue에서 작동 할 수 있습니까?
Mgetz

@Mgetz 예. 아뇨. 이 질문은 다른 날에 비공개로 "실제로"요청되었고, 그 대답은 "Clang / Win이 깨지지 않았습니다. 코드는 항상 끊어 졌지만 주류 툴체인 콤보는 결코 당신에게 귀찮게하지 않습니다. "여기에 쓰려면 : P
궤도의 가벼움 경주

2
참고로, 이것은 VS 2019에서 /permissive-(적합성)으로 컴파일되지 않으며 일반적으로 어쨌든 사용해야합니다.)
ChrisMM

1
@ChrisMM 참으로! 적합성 모드 해제 는 퍼즐의 일부였습니다. (우리는 그것을 조사하기 전에 그것을 몰랐습니다!) 그리고 나의 대답은 그것을 지적합니다 : P
궤도에서 가벼움 경주

답변:


15

이 표준은에 컴파일이 필요하지 않습니다 어떤 툴체인!

먼저 vector<bool>이상하고 아래 첨자를 기억 std::vector<bool>::reference하면 실제가 아니라 라는 프록시 유형의 임시 객체를 얻을 수 있습니다 bool&.

오류 메시지는 const일반 template <typename T> std::swap(T& lhs, T& rhs)구현 에서이 임시를 lvalue 가 아닌 참조에 바인딩 할 수 없음을 알려줍니다 .

확장!

그러나 libstdc ++ 는에 대한 과부하정의std::swap(std::vector<bool>::reference, std::vector<bool>::reference) 하지만 표준에 대한 확장입니다 (또는 표준에 대한 증거를 찾을 수 없음).

libc ++ 도이 작업을 수행합니다 .

아직도 사용하고있는 Visual Studio stdlib 구현 은 그렇지 않지만 부상에 모욕을 더하기 위해 VS에서 임시 값을 lvalue 참조바인딩 할 수 있습니다 (적합성 모드를 사용하지 않는 한). 표준 "generic" std::swap함수는 엄격한 Clang 컴파일러 대신 VS 컴파일러를 사용할 때까지 작동합니다.

그 결과, 3 가지 툴체인 모두에 대한 확장에 의존하고 있으며 Windows의 Clang 조합은 실제로 엄격한 규정 준수를 나타내는 유일한 도구입니다.

(제 생각에,이 세 가지 툴체인 은 이것을 진단해야 하므로 이번에 는 이식 할 수없는 코드를 배송하지 않았습니다. 😊)

지금 무엇?

자신 만의 전문화를 추가 std::swap하고 std::vector<bool>::reference싶을 수도 있지만 표준 유형에서는이 작업을 수행 할 수 없습니다. 실제로, libstdc ++ 및 libc ++가 확장으로 추가하기로 선택한 과부하와 충돌합니다.

따라서 이식성과 호환성 을 유지하려면 코드를 변경해야합니다 .

아마도 좋은 구식입니다 :

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

또는 원하는 것을 정확하게 수행하는 특수 정적 멤버 함수를 사용 하십시오 .

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

다음과 같이 철자가 가능합니다.

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

에 관해서는 AFAIK 는 아니지만 그렇게 할 수 있습니다. 적합한 코드를 위반하지 않는 한 구현을 확장하여 깨진 코드를 "확인"할 수 있습니다.
NathanOliver 19

@ NathanOliver-ReinstateMonica 글쎄요. 하지만 적어도 그러한 것들의 사용을 진단 할 필요는 없습니까? eel.is/c++draft/intro.compliance#8
궤도의 가벼움 경주

@LightnessRaceswithMonica이 확장을 금지하는 언어가 있습니까?
Mgetz

@Mgetz 죄송합니다, 모든 현존하는 언어에 능통하지 않으므로 답변을 드릴 수 없습니다
Orbit의 Lightness Races

이 문서에 따라 잘못된 확장을 사용하는 것이 확실하지 않습니다 . 그들은 std::vector<bool>::reference실제로 아무 것도 형성되지 않는 과부하를 추가했습니다 . 나에게는 그것이 char * foo = "bar";잘못 된 것이므로 진단이 필요할 것 같습니다 .
NathanOliver 19
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.