我实现了我的重载operator==以将我std::pair<...>的与std::string. 但由于某种原因,编译器找不到这个重载。它可以与什么连接?
重现错误的代码:
#include <algorithm>
#include <string>
#include <utility>
#include <vector>
typedef std::pair<std::string, int> RegPair;
bool operator==(const RegPair& lhs, const std::string& rhs)
{
return lhs.first == rhs;
}
int main()
{
std::vector<RegPair> sequence;
std::string foo("foo");
std::find(sequence.begin(), sequence.end(), foo);
}
错误文字:
GNU GCC:
错误:在 '__first. __gnu_cxx::__normal_iterator<_Iterator, _Container>::operator* with _Iterator = std::pair, std::allocator >, int>*, _Container = std::vector, std::allocator >, int>, std::分配器,std::allocator >, int> > > == __val'
铛:
错误:二进制表达式的操作数无效('std::pair, int>' 和 'std::basic_string const')
来自进行翻译的链接的答案不正确/不准确。ADL 搜索不会以任何方式替换/排除常规搜索,而只是对其进行补充。
正确的情况描述如下:
正常查找是从标准库中
==的函数模板定义调用运算符的位置执行的。std::find它只查找从该位置可见的名称。很明显,上面的运算符定义
==从那里是不可见的。ADL 查找是在关联的,并且仅在关联的命名空间上执行的,并且在调用
std::find代码中调用函数时查看这些命名空间。关联的命名空间集是根据6.4.2/2中描述的规则构建的。std::find在这种情况下,上述运算符的定义从调用点==完全可见。但是这个定义是在全局命名空间中进行的。在这种情况下,只有空格与 ADL 相关联std,因为两个比较参数都属于空格std。因此,ADL 不考虑全局命名空间,也找不到此定义。据称 ADL 停止进一步搜索定义
operator ==正是因为operator ==已经在内部找到了一些定义的说法std是不正确的。ADL 始终仅在关联的命名空间中查找名称。与常规查找不同,ADL 永远不会将搜索范围扩展到关联的命名空间之外,无论那里是否找到了某些东西。同样的问题可以通过下面的小例子来说明
使用此声明顺序,正常的名称查找查找从点 1 可见的名称,但 ADL 查找查找从点 2 可见的名称,但仅在关联的命名空间中。全局命名空间没有关联,所以
void bar(N::S s)找不到声明,也没有编译代码。在最初的版本中,如果我们以某种方式将全局命名空间“拉”为 ADL 的关联命名空间,那么该运算符
==将立即开始通过 ADL 定位。例如,让我们在全局命名空间中声明一些可以转换为的虚构类型std::string并将其用作搜索的键比较运算符的定义不需要更改。代码将立即开始编译并使用此比较运算符。
另一个看似“无辜”的替换选项将使代码编译,是使该对的第二个成员成为全局命名空间中的类型
无需更改任何其他内容 - 这已经足以关联 ADL 的全局命名空间。
问题是它
std::find是一个模板函数,因此operator==ADL(参数类型相关搜索)在搜索时发挥作用。两个函数参数 (
std::pair和std::string) 都在同一个命名空间 (::std) 中,因此 ADL 开始在该命名空间中查找。同时,至少在那里定义一些就足够了operator==,因为名称匹配(名称查找)是在定义合适的重载之前执行的。由于
operator==肯定会找到一个匹配的名称(<string>至少有一个比较运算符std::string与某物在同一文件中声明),因此算法停止工作。您的重载位于全局命名空间(即外部::std)中,不会到达队列。这篇文章是对James McNellis回复的粗略翻译。