簡體   English   中英

不相關的已刪除運算符會更改重載決策的行為

[英]Unrelated deleted operator changes behaviour of overload resolution

我今天遇到了一個奇怪的情況,聲明一個帶有某些參數的已刪除運算符改變了看似無關的代碼的行為。

我將它減少到以下。 從這開始:

namespace N 
{
    enum E { A, B };

    struct C 
    {   
        C(E);
    private:
        C(int);
    };  
}

N::E operator|(N::E, N::E);

namespace N
{
    void Waldo()
    {   
        C(A | B); 
    }   
}

請注意,C有兩個構造函數,一個是公共的,另一個是私有的。 此代碼編譯,表明正在選擇公共重載,因此表達式為A | B A | BE型。 反過來,這意味着operator|(N::E, N::E)已匹配(否則AB將進行隱式轉換為整數, A | B的類型將為int ,私有構造函數將為匹配。

到現在為止還挺好。 現在我定義一個新的枚舉類型F和一個刪除的operator| 涉及F:

namespace N 
{
    enum E { A, B };

    struct C 
    {   
        C(E);
    private:
        C(int);
    };  
}

N::E operator|(N::E, N::E);

namespace N
{
    enum F {};
    int operator|(F, int) = delete; 

    void Waldo()
    {   
        C(A | B); 
    }   
}

現在代碼沒有編譯,說C(int)是私有的。 這表明現在是A | B A | B類型為int ,表示operator|(N::E, N::E)不再匹配。

為什么添加刪除的operator|(F, int)會使operator|(F, int) operator|(N::E, N::E)停止匹配?

首先,注意聲明為delete d是無關緊要的,因為刪除的函數仍然參與重載解析。

現在,重載決議。 參看 13.3.1.2/3:

構建了三套候選職能,指定成員候選人非成員候選人內置候選人

(沒有成員候選者,因為E不是類類型。)我們知道運算符重載是由非限定查找找到的。 所以當我們查閱3.4.1(“不合格的查找”)時,我們發現了這一點

一旦找到名稱的聲明,名稱查找就會結束。

由於您在命名空間N引入了第二個運算符重載,因此首先找到它,並且名稱查找停止。 此時,重載集由int N::operator|(N::F, int)和內置運算符組成。 繼續在13.3.1.2/6:

重載決策的候選函數集是成員候選者,非成員候選者和內置候選者的聯合。

只有內置是可行的(因為你不能隱含地將E轉換為F ),因此它被選中。

解決問題的方法很簡單。

把你的operator| 在與類型相同的命名空間中。 現在,ADL(參數依賴查找)啟動, 即使存在不相關的operator|也可以找到它 也可見。

實例 注意N::operator| 發現盡管| namespace Z

為類型重載自由運算符的適當位置是類型所在的namespace ,而不是全局命名空間。

暫無
暫無

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

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