我有这样的代码:
#include <vector>
#include <utility>
int main()
{
std::vector<bool> vb{true, false};
std::swap(vb[0], vb[1]);
}
除了关于vector<bool>
的理智性的争论之外,这种方法还可以很好地用于:
然后我尝试在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不起作用?
答案 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::swap
和std::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]);