更多 C++ 習語/Barton-Nackman 技巧
外觀
支援過載運算子,而無需依賴名稱空間或函式模板過載解析。
發明者最初稱之為受限模板擴充套件,儘管這個詞從未被廣泛使用。
John Barton 和 Lee Nackman 於 1994 年首次發表了這種習語,以解決當時 C++ 實現的侷限性。[1] 儘管它不再需要用於其最初目的,但當前標準仍然支援它。
在 Barton 和 Nackman 最初開發這種習語時,C++ 不支援函式模板的過載,許多實現仍然不支援名稱空間。這在為類模板定義運算子過載時會造成問題。請考慮以下類
template<typename T>
class List {
// ...
};
定義相等運算子的最自然方法是在名稱空間範圍內定義為非成員函式(並且由於當時的編譯器不支援名稱空間,因此在全域性範圍內)。將operator==定義為非成員函式意味著兩個引數被對稱地處理,而如果一個引數是物件的this指標,則不會發生這種情況。這樣的相等運算子可能看起來像這樣
template<typename T>
bool operator==(List<T> const & lft, List<T> const & rgt) {
//...
}
然而,由於當時的函式模板無法過載,並且由於將函式放在其自己的名稱空間中在所有平臺上都不起作用,這意味著只有一個類可以擁有這樣的相等運算子。對第二種型別執行相同操作會導致歧義。
該解決方案透過在類中將運算子定義為友元函式來實現
template<typename T>
class List {
public:
friend bool operator==(const List<T> & lft,
const List<T> & rgt) {
// ...
}
};
現在例項化模板會導致一個非模板函式被注入到全域性範圍內,其引數型別是具體、固定的型別。這個非模板函式可以透過函式過載解析以與任何其他非模板函式相同的方式進行選擇。
透過提供友元函式作為透過好奇的遞迴模板模式繼承的基類的一部分,可以推廣實現
template<typename T>
class EqualityComparable {
public:
friend bool operator==(const T & lft, const T & rgt) { return lft.equalTo(rgt); }
friend bool operator!=(const T & lft, const T & rgt) { return !lft.equalTo(rgt); }
};
class ValueType :
private EqualityComparable<ValueType> {
public:
bool equalTo(const ValueType & other) const;
};
- Barton-Nackman 技巧 在維基百科上。
- ↑ Barton, John J.; Nackman, Lee R. (1994). 科學與工程 C++:帶高階技術和示例的介紹. Addison-Wesley. ISBN 0-201-53393-6.