2011-09-09 31 views
5

,纔有可能和/或有用的用戶定義文字以限定operator "" (...)爲朋友功能?的C++ 0x,與操作者的朋友「」()

class Puzzle { 
    friend Puzzle operator "" _puzzle(const char*, size_t); 
    ... 
}; 
void solve(Puzzle); 
int main() { 
    solve("oxo,xox"_puzzle); 
}; 

我在想「有用」,尤其是,因爲operator ""應在命名空間中只能被定義規則的 - 而不是一個重要原因在於_開始的名稱在全局命名空間保留。這是friend這裏違反這條規則嗎?所以,這個不太完美的封裝沒有好處,對吧?

回答

2

標準地址這直接在它提到用戶定義的文字的聲明任何限制的唯一場所,§13.5.8/ 2:

的聲明,其聲明符-id爲一個文字的操作員-id應是一個命名空間範圍的函數或函數模板(它可能是一個友元函數(11.3)),函數模板的顯式實例化或專業化,或使用聲明(7.3.3)的聲明。

如果朋友也在名稱空間範圍內聲明,那麼在類或名稱空間範圍內的定義沒有區別。請注意,在命名空間範圍內沒有要求定義的問題,您的問題與目前的措辭一致。

如果在命名空間內未聲明,因爲它無法通過ADL可以發現,朋友可以私下它是由正規不合格的名稱查找範圍類中使用。這是聲明不是外部接口的文字操作符的唯一方法。

如果朋友是在類模板內部定義的,那麼模板的兩個實例將在名稱空間範圍內生成兩個相同名稱的函數,即使它們在類範圍外都不可見,也會發生衝突。

+0

我真的認爲我已經在某處讀過它了,後綴*應該*只能在**命名空間**內聲明。我不記得在哪裏 - 但這只是一個建議,而不是要求。因此,這可能是「良好實踐」的唯一提示。關於**模板**好友功能的好處。對於通常的* friend *模式,這不是問題,friend函數至少有一個參數是一個類實例本身 - 那麼就沒有命名問題。 – towi

+1

我記得在早期的立場文件中看到類似的東西。嘗試n2378.pdf第5節:成語。在這裏他們說:1.這些函數不是通過ADL通過文字調用而不是通過顯式的操作符形式找到的。這將引誘在全球範圍內的佈局。 3.即使在不使用文字的代碼中,這也會導致衝突。所以把文字操作放到一個命名空間中,並且使用一個使用指令將它們拉到全局級別。 – emsr

+0

我只是想說明你可以*不*在類中私有地使用朋友函數,參見[這個問題](http://stackoverflow.com/questions/8207633/whats-the-scope-of-inline-friend -功能)。 – Xeo

0

根據標準,是的,朋友聲明應該是合法的。 順便說一句,用戶代碼的名稱很好,因爲即使在全局名稱空間中它也以下劃線開頭。

friend聲明將允許操作員訪問類的私有數據。

,我開始懷疑,朋友字面運營商的效用。由於用戶定義的運算符只能有少量參數列表,因此無法將類放入參數中。因此,現在有依賴於參數的查找方式來找到正確的功能。我對嗎?

+0

我覺得ADL可以使用,但必須尋找一個'爲const char無論你的運營商是爲定義*'說法或。但無論如何,我也懷疑它的實用性:好吧,您可以訪問私人數據,但是您仍然需要調用構造函數。順便說一句:johannes(其他anwers評論)指出,名稱不是'_puzzle',而是'運算符'「_puzzle',因此不會以下劃線開頭。 – towi

+0

是的,根據13.5。對於文字操作員來說,8/7定期查詢將佔上風。我遇到名稱問題。我在17.6.4.3.5掛了電話,它保留了文字後綴*,沒有*前面的下劃線。 – emsr

+1

我認爲他們設計的主要目的是讓他們允許一個庫的唯一實現,比如說十進制。用戶定義的文字操作符爲詞法分析器提供了一個鉤子。 – emsr

1

在情況下,它有助於語法,這裏是我如何在一個類中,操作人員本身是一個命名空間聲明友用戶定義的字面操作:

class Integer; 
namespace literals { 
    Integer operator "" _I (const char *); 
} 

// Infinite precision integer 
class Integer { 
    public: 

    // Basic constructor & destructor 
    Integer(); 
    ~Integer(); 

... rest of the interface ... 

    // Literal operator 
    friend Integer literals::operator "" _I (const char *); 

    private: 

    struct Detail; 
    std::unique_ptr<Detail> detail; 

}; 

用戶拉在運營商與using namespace literals;聲明只有當他們想要它。 (實際上,所有這些都在父命名空間中,但你明白了)。