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

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

#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과 함께 작동하지 않는 이유는 무엇입니까?



답변

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

먼저 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]);