本文最后更新于:2022年4月26日 下午
前情提要 假如我们需要为QList<T>
的某个类型编写特殊的operator==
那就需要考虑是编写普通函数还是模板特化了
模板函数与非模板函数的重载决议步骤 1.为这个函数名建立候选函数集合
与被调用函数名字相同的任意普通函数
任意函数模板实例化,在其中,模板实参推断发现了与调用中所用函数实参相匹配的模板实参
2.确定哪些普通函数是可行的(如果有可行函数的话)。候选集合中的每个模板实例都可行的,因为模板实参推断保证函数可以被调用 3. 如果需要转换来进行调用,根据转换的种类排列可靠函数,记住,调用模板函数实例所允许的转换是有限的
如果只有一个函数可选,就调用这个函数
如果调用有二义性,从可行函数集合中去掉所有函数模板实例
4.重新排列去掉函数模板实例的可行函数
如果只有一个函数可选,就调用这个函数
否则,调用有二义性
问题 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 template <class T >class MyList {public : bool operator ==(const MyList<T>& l) const { return a == l.a; } bool operator !=(const MyList<T>& l) const { return a != l.a; } T a; };bool operator ==(const MyList<int >& lhs, const MyList<int >& rhs) { return lhs.a == rhs.a; }bool operator !=(const MyList<int >& lhs, const MyList<int >& rhs) { return !(lhs == rhs); }int main (void ) { MyList<int > list, list2; list == list2; list != list2; }
如上图 调用!=
运算符会报错
1 2 3 E:\Qt5.14.2\Projects\HelloWorld\hellodialog.cpp:44: error : ambiguous overload for 'operator==' (operand types are 'const MyList<int >' and 'const MyList<int >') return !(lhs == rhs); ~~~~^~~~~~
也就是类模板的成员函数 和 普通函数产生二义性(都是完美匹配)
但是你可能说了:函数模板优先级不应该低于普通函数吗,应该调用普通函数才对呀
我也这么认为
但是有没有可能,成员函数operator==
不是模板函数呢?
因为唯一的模板适用于指示模板类的类型的
一旦类的类型确定,operator==
的参数也就确定了
在类模板作用域中,可以直接使用模板名而不提供实参 —— 《C++ Primer》 P589
即,以下两种皆可
1 2 bool operator ==(const MyList<T>& l) const ;bool operator ==(const MyList& l) const ;
这就是普通函数
operator==
根本不是模板函数
导致模板函数匹配规则不适用
(以上我猜的)
第二点 :
1 2 3 E:\Qt5.14 .2 \Projects\HelloWorld\hellodialog.cpp:64 : warning: ISO C++ says that these are ambiguous, even though the worst conversion for the first is better than the worst conversion for the second : list == list2; ^~~~~
这个是warning
,如果按以上分析,此时虽然要经过const
转换,这应该也得是二义性错误,为什么此时普通函数更好,不解
正确做法 想要不冲突,最好不要产生模板函数和普通函数的重载
最好进行模板特化
1 2 3 4 5 6 7 8 9 10 template <>bool MyList<int >::operator ==(const MyList<int >& l) const { return l.a == a; }template <>bool MyList<int >::operator !=(const MyList<int >& l) const { return !(l == *this ); }
PS :注意模板特化要写在调用之前,否则会导致产生新模板实例
寄 Ref C++普通函数与模板函数以及特化函数重载的优先级问题 - Ricky.K - 博客园
聊聊C++模板函数与非模板函数的重载 - origins - 博客园
函数模板与同名的非模板函数重载的时候,两者调用顺序_九月丫头的博客-CSDN博客
类模板函数特化(专用化)specialization of …… after instantiation_布鲁克零三四四的博客
C++模板的偏特化与全特化 | Harttle Land