@AlexanderGessler 的回答在几个细节上是不完整的。那么让我们为两种表达式和两种类型都运行编译器,好吗?
表达式 1
cout << (v1 == v2) << endl;
首先,对于type1
and type2
,非限定名称查找从main()
函数范围向外开始,并operator==
在全局范围内找到您自己的函数。
其次,参数相关名称查找(ADL) 查找from的函数模板operator==
。实际上,ADL 找到了更多的函数模板(来自和的那些,因为您也包含了这些标题)。std::pair
namespace std
std::operator==
std::vector
std::string
注意:ADL 还会找到 的匹配项type2
,因为它的基类type1
将添加namespace std
到其关联命名空间的集合中。
3.4.2 依赖于参数的名称查找 [basic.lookup.argdep]
— 如果 T 是类类型(包括联合),则其关联的类是:类本身;它所属的类别(如有的话);及其直接和间接基类。其关联名称空间是其关联类是其成员的名称空间。
第三,对所有找到的函数模板进行模板参数推导。对于type1
,只有函数模板 forstd::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
它将推导出totype1
或的第三个模板参数type2
。
在 内std::find
,找到一个调用operator==
。同样,将首先执行普通查找。然而,这发生在内部namespace std
。它将找到几个operator==
函数模板(for和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
与全局命名空间)找到不同的名称。