다음과 같은 코드가 있습니다.
#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]);