模板友元运算符重载必须优先于同名成员运算符重载吗?
问题原因剖析
这本质是类作用域内的名字查找优先级和函数模板特化语法的冲突问题,具体拆解如下:
第一种编译通过的情况
在声明成员operator==之前,先写友元声明friend bool operator== <> (const T& l, const Foo<T>& r):
- 此时编译器在类作用域里查找
operator==,因为还没声明成员版本,会自动去全局作用域找之前已经声明的全局函数模板template<typename T> bool operator==(const T&, const Foo<T>&)。 - 后面的
<>是模板特化标记,表示要把这个全局模板特化为对应当前T版本的函数,作为类的友元,这个语法完全合法,因此编译通过。
第二种编译失败的情况
先声明成员bool operator==(const Foo<T>& r),再写友元声明:
- 此时编译器在类作用域内已经找到了成员函数
operator==,根据C++的名字查找规则,类内部的名字优先级高于全局名字,所以会把operator==解析成这个成员函数。 - 但成员函数
operator==不是模板函数,不能用<>来做特化/实例化标记,这违反了语法规则,编译器因此报错“operator==被声明为非函数”——本质是它把operator==当成了非模板的成员函数,而非你期望的全局模板函数。
替代解决思路(无需调整顺序)
如果不想调整声明顺序,可以在友元声明里显式限定全局作用域,强制编译器去全局找模板:
friend bool ::operator== <> (const T& l, const Foo<T>& r);
这样即使类内已经有成员operator==,编译器也会优先解析全局的模板版本,就能正常编译。
内容的提问来源于stack exchange,提问作者Daniel Engel
相关产品推荐
相关产品推荐

