2010-01-05 70 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正是我們期望看到的。

相關問題