C++ 为什么';t std::矢量交换工作<;布尔>;“叮当声/胜利”下的元素?

C++ 为什么';t std::矢量交换工作<;布尔>;“叮当声/胜利”下的元素?,c++,visual-studio,clang,c++17,std,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]); } #包括 #包括 int main() { 向量vb{true,false}; std::swap(vb[0],vb[1]); } 撇开关于vector是否健全的争论不谈,这在以下方面起到了很好的作用:

我有这样的代码:

#include <vector>
#include <utility>

int main()
{
   std::vector<bool> vb{true, false};
   std::swap(vb[0], vb[1]);
}
#包括
#包括
int main()
{
向量vb{true,false};
std::swap(vb[0],vb[1]);
}
撇开关于
vector
是否健全的争论不谈,这在以下方面起到了很好的作用:

  • 麦克的叮当声
  • Visual Studio for Windows
  • 用于Linux的GCC
然后,我尝试在Windows上使用叮当声构建它,并收到以下错误(节略):

错误:调用“swap”时没有匹配的函数
std::swap(vb[0],vb[1]);
^~~~~~~~~
注意:候选函数[with _Ty=std::_Vb_reference,$1=void]不可行:第一个参数需要一个l值
内联无效交换(_Ty&_Left,_Ty&_Right)_NOEXCEPT_COND(不可移动)_move_constructible_v&&
我感到惊讶的是,不同实现的结果有所不同


为什么它不能在Windows上与Clang一起工作?

标准不要求在任何工具链上编译它

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

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

分机! 然而,事实证明libstdc++for
std::swap(std::vector::reference,std::vector::reference)
,但这是对该标准的扩展(或者,如果在其中,我找不到任何证据)

libc++

我猜您仍在使用的VisualStudio stdlib实现不会这样做,但在VS中会雪上加霜(除非您使用的是一致性模式),因此标准的“generic”,std::swap函数会一直工作,直到您将VS编译器替换为更严格的Clang编译器

因此,您一直依赖于三个工具链上的扩展,这三个工具链对您都有效,而Windows上的叮当声组合是唯一一个真正表现出严格遵从性的组合


(在我看来,这三个工具链使你在这段时间内没有发布不可移植的代码。关于,但不应该这样做,他们被允许这样做。只要他们不破坏一致的代码,他们就可以扩展实现,使破坏的代码“OK”.@NathanOliver:嗯,好吧。不过,他们难道不需要至少诊断一下这些东西的用法吗?@LightnessRaceswithMonica有任何语言禁止这种扩展吗?@Mgetz对不起,我不熟悉所有现存的语言,所以我无法回答,我不确定是否使用了根据本文档格式不正确的扩展t适用。他们添加了一个重载,该重载采用
std::vector::reference
,因此实际上没有任何东西是格式不正确的。对我来说,使用类似
char*foo=“bar”
的东西需要进行诊断,因为这是格式不正确的。所以我想需要澄清的是:是
操作符[]的结果吗
一个左值?并且
std::swap
可以对右值和x值进行操作吗?@Mgetz是的。不。按照这个顺序。这个问题前几天私下里被问到“真实的”,我认为答案是正确的,这很有趣“Clang/Win没有被破坏;代码在整个过程中都被破坏了,但是主流的工具链组合从来没有费心告诉你”写在这里:作为一个参考,这不是在VS2019中编译的
/permissive-
(一致性),它通常应该被使用;)@ChrisMM确实!一致性模式关闭是难题的一部分。(尽管我们在调查之前并不知道!)我的回答确实指出:P@ChrisMM不再是了!
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>&&