繁体   English   中英

模板类中的朋友操作员声明

[英]Friend operator declaration in a template class

我有一个很好的问题,在模板类中声明的友元运算符和类的显式实例化,如下所示:

template<class T>
class IneqCmp{
    friend bool operator!=(T a, T b){
        return !(a==b);
    }
};

struct IntCont{
    int x;
    bool operator==(IntCont that) const{
        return x==that.x;
    }
};
template class IneqCmp<IntCont>;
int main(){
    IntCont a{1}, b{2};
    while(a!=b);
}

我认为operator!=(IntCont,IntCont)应该在IneqCmp <IntCont>的实例化时实例化,但事实并非如此。 为什么?

上面代码的问题不在于是否定义了operator!= ,而是查找*永远不会找到它。

当你将一个函数声明为一个类的朋友时,声明是奇怪的 ,因为它声明了一个名称空间级函数,但它的声明只能通过封闭类型的ADL来获得。 因为你的operator!=不将IneqComp作为两个参数中的任何一个,所以实际上不可能通过查找来查找。

如果你想要做的是提供operator!=的默认实现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添加到lookup中。 当编译器在main遇到a != b时,它将尝试使用在当前作用域中定义的operator!=IntCont及其基础以及定义IntCont及其基数的命名空间。


*如果要验证操作符实际已生成,请尝试添加它:

bool operator!=(IntCont a, IntCont b){
    return !(a==b);
}

如果由于IneqCmp的实例化而定义了运算符,则会触发编译器错误。 或者,您可以编译并检查生成的符号文件。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM