@AlexanderGessler 的回答在几个细节上是不完整的。那么让我们为两种表达式和两种类型都运行编译器,好吗?
表达式 1
cout << (v1 == v2) << endl;
首先,对于type1 和type2,非限定名称查找从main() 函数范围向外开始,并在全局范围内找到您自己的operator== 函数。
第二,依赖于参数的名称查找(ADL)从namespace std 中找到std::pair 的函数模板operator==。实际上,ADL 找到了更多 std::operator== 函数模板(来自 std::vector 和 std::string,因为您也包含了这些标题)。
注意:ADL 还会找到 type2 的匹配项,因为它的基类 type1 会将 namespace std 添加到其关联命名空间的集合中。
3.4.2 依赖于参数的名称查找 [basic.lookup.argdep]
——如果 T 是一个类类型(包括联合),它的关联类是:
班级本身;它所属的类别(如有的话);及其
直接和间接基类。其关联的命名空间是
与其关联的类是其成员的命名空间。
第三,模板参数推导对所有找到的函数模板进行。对于type1,只有std::pair 的函数模板才能在参数推导中保留下来(并且它将其模板参数分别推导出为std::string 和int)。但是,对于type2,没有适合的模板参数集,因为type2 不是std::pair 模板的实例化。
第四,重载分辨率发挥作用。对于type1,您自己的函数operator== 和std::operator== 函数模板的等级相同(精确匹配)。因此,抢七将选择您的非模板函数。对于type2,只有一个可行的函数,因此重载决议不会发挥作用,您的函数将被选中。
结论 1:type1 和 type2 将给出相同的答案(选择了您的版本),尽管原因不同。
表达式 2
cout << (find(vec.begin(), vec.end(), v2) != vec.end()) << endl;
这里我们需要先解决对find的调用。由于您的using namespace std;,非限定名称查找已经找到(没有双关语)std::find,但即使没有 using 指令,std::vector 迭代器上的 ADL 也会找到它。它会将std::find 的第三个模板参数推导出为type1 或type2。
在std::find 内,找到了对operator== 的调用。同样,将首先执行普通查找。但是,这发生在namespace std 内部。它将找到几个operator== 函数模板(用于std::vector、std::string 和std::pair)。一旦在不合格的名称查找过程中找到一个范围内的候选对象,名称查找的这个阶段就会停止。
但是,ADL 仍在执行中。请注意,尽管全局命名空间不是type1 的关联命名空间因为它只是namespace std 中的类的类型定义。所以对于type1,ADL 没有发现任何新东西。相反,type2 确实将全局命名空间作为其关联的命名空间,因此 ADL 将在这种情况下找到您的 operator== 函数模板。
对于type1,template-argument-deduction 查找std::string 和int 作为operator== 函数模板std::pair 的模板参数。对于type2,同样没有适合的模板参数集,因为type2 不是std::pair 模板的实例化。
剩下的就是重载决议。对于type1,只有一个可行的函数(std::operator== 模板的实例),重载决议不起作用。对于type2,也只有一个可行的函数(可行是因为它只需要标准的derived-to-base 转换)。因此,重载决议也不会发挥作用。
结论 2:对于type1(std 版本)和type2(您的版本),您会得到不同的结果。
总结
仅仅因为这些事情在不同命名空间中的多个重载会变得非常棘手,这里有一个包含三位一体的汇总表(名称查找、参数推导和重载解析)。对于每个阶段和每种类型,我都列出了该阶段之后幸存的候选人。底行显示被调用的函数。
表达式 1
+---------------------+-----------------+-----------------+
| phase | type1 | type2 |
+---------------------+-----------------+-----------------+
| unqualified lookup | ::operator== | ::operator== |
| ADL | std::operator== | std::operator== |
+---------------------+-----------------+-----------------+
| argument deduction | ::operator== | ::operator== |
| | std::operator== | |
+---------------------+-----------------+-----------------+
| overload resolution | ::operator== | ::operator== |
+---------------------+-----------------+-----------------+
表达式 2
+---------------------+-----------------+-----------------+
| phase | type1 | type2 |
+---------------------+-----------------+-----------------+
| unqualified lookup | std::operator== | std::operator== |
| ADL | | ::operator== |
+---------------------+-----------------+-----------------+
| argument deduction | std::operator== | ::operator== |
+---------------------+-----------------+-----------------+
| overload resolution | std::operator== | ::operator== |
+---------------------+-----------------+-----------------+
请注意,非限定查找会根据其开始的范围(全局范围内的函数范围与命名空间范围)找到不同的名称,并且 ADL 类似地根据被认为关联的命名空间找到不同的名称(namespace std 与全局命名空间)。