为什么std :: swap在Clang / Win下的vector <bool>元素上不起作用?

时间:2019-11-01 13:39:49

标签: c++ visual-studio clang c++17 std

我有这样的代码:

#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不起作用?

1 个答案:

答案 0 :(得分:15)

该标准不需要在任何工具链上进行编译!

首先回想一下vector<bool>很奇怪,用下标给您一个名为std::vector<bool>::reference的代理类型的临时对象,而不是实际的bool&

错误消息告诉您,它无法将此临时绑定绑定到通用const实现中的非template <typename T> std::swap(T& lhs, T& rhs)左值引用。

扩展!

但是,事实证明std::swap(std::vector<bool>::reference, std::vector<bool>::reference)的libstdc ++ defines an overload,但这是对标准的扩展(或者,如果有,我找不到任何证据)。

libc ++ does this too

我猜想您仍在使用的Visual Studio stdlib实现不会,但是会给VS中的伤害you can bind temporaries to lvalue references增加侮辱(除非您重新使用一致性模式),因此标准的“泛型” std::swap函数将起作用,直到您将VS编译器替换为更严格的Clang编译器为止。

因此,您一直依赖于它为您服务的所有三个工具链的扩展,并且Windows上的Clang组合是唯一真正表现出严格合规性的工具。

(在我看来,这三个工具链should have diagnosed this因此您一直没有发布不可移植的代码。)

现在怎么办?

添加std::swapstd::vector<bool>::reference自己的专业化也许很诱人,但是对于标准类型,您不允许这样做。确实,这将与libstdc ++和libc ++选择添加为扩展的重载冲突。

因此,为了便于携带和兼容,您应该更改代码

也许是一个很好的老式:

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

或使用the special static member function that does exactly what you wanted

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

还可以如下拼写:

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