更多 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.