2010-01-05 71 views

回答

13

这是纯粹的讨厌。首先我们来看看互换的声明:现在

template<class T> 
void swap(T &left, T &right); 

operator[]()bitset有两个重载:

bool operator[](size_type _Pos) const; 
reference operator[](size_type _Pos); 

这里referencebitset::reference,在bitset嵌套类,有效地充当代理参考其中一个基础位。它封装的是bitsetbitset中的一个位置。由于swap的声明,选择了第二个过载,我们正在交换两个bitset::reference。现在,这里变得讨厌。让我们来看看一个典型的实现互换:

template class<T> swap(T &left, T &right) { 
    T temp = left; 
    left = right; 
    right = temp; 
} 

的问题是,leftright是一个bitset::reference两个引用。它们具有相同的基础数据(因为它们是代理;同样意味着两者都指向相同的bitset!),它们只是封装了bitset中的不同位置。因此,认为它是这样left是位置0在一些bitsetright是位置1在一些bitsetbitsetbitsetleft相同!让我们永远把这个bitset称为BS(故意选择)。

所以,

T temp = left; 

tempBS位置0。

left = right; 

套位置0中BS离开位置1(同时改变temp位置0!)

right = temp; 

套位置1右位置BS 0(只设为位置1在BS!)。所以在这个混乱的结尾有0的位置是什么位置1和位置1是不变的!现在,因为位置0是LSB,位置1是MSB,所以“10”变成“11”。丑陋。

可以解决这个问题了template specialization

namespace std { 
    template<> 
    void swap<bitset<2>::reference>(
     bitset<2>::reference &left, 
     bitset<2>::reference &right 
    ) { 
     bool temp = (bool)left; 
     left = (bool)right; 
     right = (bool)temp; 
    } 
} 

然后:

int main() { 
    bitset<2> test(string("10")); 
    cout << test; // Prints "10" 
    swap(test[0], test[1]); 
    cout << test; // Prints "01", hallelujah! 
} 
+1

干得好!令人难以置信的是,甚至连C++ 0x都没有提到与位集相关的'swap'。 – Potatoswatter 2010-01-05 05:52:49

+1

这是否真的编译? 'test [0]'是暂时的,你不能参考... – Barry 2015-09-22 21:53:23

2

实际上,因为test[i]返回一个bitset参考右值,我真的不知道如何swap可以编译在这里。我的编译器(G ++ 4.3.3)告诉我:

test.cpp:12: error: no matching function for call to 
    'swap(std::bitset<2u>::reference, std::bitset<2u>::reference)' 
/usr/include/c++/4.3/bits/stl_move.h:80: note: candidates are: 
    void std::swap(_Tp&, _Tp&) [with _Tp = std::bitset<2u>::reference] 
+2

是啊。 MSVC接受代码,在swap()中没有什么好处。 – 2010-01-05 02:27:01

+1

@HansPassant VS接受这个代码是因为[bug](https://connect.microsoft.com/VisualStudio/feedback/details/775818/vc11-non-const-lvalue-reference-incorrectly-binds-to-rvalue)它允许非常量左值引用绑定到右值。我提出了错误(帮助说服微软修复它)并添加了一个链接到这个帖子,作为这个bug的一个恶意后果的例子。我建议你(每个人)也要高举bug。 – 2013-12-28 15:00:19

2

有一个在C++来表示单个位无值类型,所以当你使用[]操作符来访问一个bitset的元素,你得到的是一个代理对象作为您请求的位的别名。分配给该代理对象将更改原始位集对象中的相应位值。

由于Victor's answer显示,您的代码不与GCC编译。但让我们假设编号为swap的电话。你会得到的代码相当于这样的:

void swap(std::bitset<2>::reference& a, std::bitset<2>::reference& b) 
{ 
    std::bitset<2>::reference tmp = a; 
    a = b; 
    b = tmp; 
} 

tmp声明初始化与a变量,但这并不制造钻头的一个副本。相反,它使得代理对象的副本,所以tmp在相同的bitset相同的比特是a指。下一行将b指定为a,该位复制来自位置a的位值,并将其存储在位位置b中。最后,将tmp分配到b。但请记住tmp仍然指的是a所指的位。阅读tmp是一样的阅读a,所以你最终得到相同的效果,你会得到,如果swap只是两行:

a = b; 
b = a; 

在你的代码,a是0和b是1,所以这些两个赋值语句,11正是我们期望看到的。

相关问题