尝试编译以下代码时(从原始代码简化):
#include <cstdlib>
#include <iostream>
#include <set>
namespace OrbitSets {
class rational;
}
bool operator<(OrbitSets::rational a, OrbitSets::rational b);
namespace OrbitSets {
// Class definition
class rational {
private:
long long numerator;
long long denominator;
public:
rational() {
numerator = 0;
denominator = 1;
}
rational(int a) {
numerator = a;
denominator = 1;
}
friend bool ::operator<(rational a, rational b);
};
}
// Ordering operations
inline bool operator<(OrbitSets::rational a, OrbitSets::rational b) {
return a.numerator * b.denominator < b.numerator * a.denominator;
}
int main() {
const OrbitSets::rational a = 5;
const OrbitSets::rational b = 3;
std::set<OrbitSets::rational> c;
c.insert(a);
if (a < b) return 1;
return 0;
}
gcc在c.insert行上抱怨它找不到运算符&lt;对于OrbitSets :: rational类,给出以下错误:
/usr/include/c++/5/bits/stl_function.h:387:20: error: no match for ‘operator<’ (operand types are ‘const OrbitSets::rational’ and ‘const OrbitSets::rational’)
{ return __x < __y; }
但是,当注释掉c.insert(a)行时,代码会正确编译,即使后两行使用相同类型的参数进行类似的比较。
我使用g ++来编译它,为什么它不能找到在较少的&lt; ..&gt;中使用的前述运算符。模板类,但能够找到它以后使用2行吗?
答案 0 :(得分:3)
当set::insert
尝试评估表达式__x < __y
以比较对象时,编译器会执行Argument-Dependent Lookup。
第一步是Unqualified Name Lookup。由于表达式在namespace std
中使用,因此该查找会找到几个函数std::operator<
(正如您在长编译器错误输出中看到的那样),并在那里停止。
然后编译器会找出&#34;关联的命名空间和类&#34;用于函数调用。由于两个参数具有相同的类类型,因此唯一关联的类是OrbitSets::rational
,唯一关联的命名空间是OrbitSets
。
由于您的operator<
位于全局命名空间中,因此关联的命名空间查找找不到它。
我不明白为什么规则[basic.argdep.lookup] /4.2不适用:
- 在关联类中声明的任何命名空间范围的朋友函数或朋友函数模板在其各自的命名空间中都是可见的,即使它们在普通查找期间不可见。
对我来说,你确实有一个名称空间范围的朋友函数,它在关联的类中声明,即使它不是第一个声明。但是g ++和clang ++都给出了同样的错误,其中至少有一个通常是正确的......
您的(a < b)
表达式不在包含任何其他operator<
的范围内,因此在这种情况下可以找到全局命名空间中的::operator<
重载集,包括您所指的那个
在任何情况下,您都可以通过在operator<
内移动namespace
OrbitSets
来解决此问题。