上面代码的问题不在于是否定义,而是查找*operator!=
永远找不到它。
当你将一个函数声明为一个类的友元时,这个声明很奇怪,因为它声明了一个命名空间级别的函数,但它的声明只能通过 ADL 在封闭类型上获得。因为您operator!=
不接受IneqComp
这两个参数中的任何一个,所以实际上不可能通过查找找到。
如果您想要做的是提供operator!=
可用于一组类型的默认实现,您可以用不同的方式解决问题。
首先,您可以IneqCmp
使用继承添加到 ADL 集中:
struct IntCont : IneqCmp<IntCont> {
// ...
};
因为 ADL 在参数的类和基类中查找,这将有效地触发内部查找,从而IneqCmp<IntCont>
找到friend
声明并因此找到自由函数。
另一种选择是添加一个命名空间,其中operator!=
将定义泛型(这样就不会在其他情况下找到它)和一个tag
类型。然后从该标签继承:
namespace inequality_comparable {
struct tag {};
template <typename T>
bool operator!=( T const & a, T const & b ) {
return !(a==b);
}
}
struct IntCont : inequality_comparable::tag {
};
bool operator==( IntCont const & a, IntCont const & b ) {
return ...;
}
int main() {
IntCont a,b;
std::cout << a != b << "\n";
}
这里的诀窍是,因为inequality_comparable::tag
它是您类型的基础,所以它会将命名空间添加inequality_comparable
到查找中。当编译器遇到它时a != b
,main
它会尝试使用operator!=
当前作用域中定义的类、类IntCont
及其基类以及定义其基类的命名空间IntCont
。
*如果要验证算子是否真的生成了,尝试添加:
bool operator!=(IntCont a, IntCont b){
return !(a==b);
}
如果由于 then 的实例化而定义了运算符IneqCmp
,则会触发编译器错误。或者,您可以编译并检查生成的符号目标文件。