簡體   English   中英

錯誤:使用復制和交換習語的交換 function 中“操作員 =”的模糊重載

[英]error: ambiguous overload for 'operator=' in swap function using the copy-and-swap idiom

在具有常量引用作為成員的 class 中使用復制和交換習語時,會發生上述錯誤。

示例代碼:

#include <iostream>
#include <functional>

using std::reference_wrapper;

class I_hold_reference;
void swap(I_hold_reference& first, I_hold_reference& second);

class I_hold_reference{
    inline I_hold_reference(const int& number_reference) : my_reference(number_reference){}
    friend void swap(I_hold_reference& first, I_hold_reference& second);
    inline I_hold_reference& operator=(I_hold_reference other){
        swap(*this, other);
        return *this;
    }
    inline I_hold_reference& operator=(I_hold_reference&& other){
        swap(*this, other);
        return *this;
    }
private:
    reference_wrapper<const int> my_reference;
};

void swap(I_hold_reference& first, I_hold_reference& second){
    first = I_hold_reference(second.my_reference); //error: use of overloaded operator '=' is ambiguous (with operand types 'I_hold_reference' and 'I_hold_reference')
}

當 Copy 賦值運算符被更改為通過引用而不是按值獲取其參數時,該錯誤已得到修復。

    inline I_hold_reference& operator=(I_hold_reference& other){ ... }

為什么這可以修復錯誤? 一種可能的含義是鏈接問題中引用的重要優化可能性丟失了。 參考文獻是這樣嗎? 這種變化的其他影響是什么?

有一個依賴此運算符的代碼庫,不存在其他成員,只有提到的引用。 是否需要以某種方式使代碼庫適應這種變化,或者它是否安全?

如果您仔細按照鏈接的描述進行操作,您會發現您必須只有一個operator=重載,並且需要按值獲取其參數。 因此,簡單地刪除operator=(I_hold_reference&&)重載將使您的代碼可編譯。

然而,這不是唯一的問題。 您的swap不會交換,而是將second個副本分配給first ,而second保持不變。

這就是你想要的:

class I_hold_reference
{
    I_hold_reference(const int& number_reference)
     : my_reference(number_reference){}

    friend void swap(I_hold_reference& first, I_hold_reference& second)
    {
        using std::swap;
        swap(first.my_reference, second.my_reference);
    }

    I_hold_reference& operator=(I_hold_reference other)
    {
        swap(*this, other);
        return *this;
    }
private:
    reference_wrapper<const int> my_reference;
};

注意:我刪除了不必要的inline ,因為成員函數是隱式內聯的。 我還在 class 內部聲明了swap function。 您可以在共享的鏈接中找到對此的解釋。

此外,在這個特定的示例中,首先不需要使用復制和交換習語。 std::reference_wrapper不是手動維護的資源,這意味着它內置了正確的復制和移動語義。因此,在這個特定示例中,編譯器生成的復制和移動運算符將具有與此處手動創建的完全相同的行為。 所以,你應該使用那些,而不是以任何方式寫你自己的。 另一方面,如果這只是一個玩具示例,並且真正的 class 中更多資源需要手動管理,那么這就是 go 的方法。

使用轉發引用&&將綁定到任何右值(臨時/轉發引用)。 這些類別也可以作為值傳遞,然后是模棱兩可的。 也就是說,一個臨時的例子是模棱兩可的,因為左值不會是(使用值重載)。

其中非常量引用永遠不能綁定到臨時轉發引用 一個const引用雖然可以,但不是模棱兩可的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM