立即修复
Do this:
namespace nsp {
bool operator==(const Foo& a, const Foo& b);
}
解决你的问题。
如果你有控制权Foo
,你可以这样做:
namespace nsp {
struct Foo {
friend bool operator==(const Foo& a, const Foo& b) {
return true;
}
};
}
这是最佳的,如果Foo
是一个模板类。
您的解决方案出了什么问题
这里发生的事情是这样的optional
is in std
(or boost
或其他)并在该名称空间中尝试执行nsp::Foo == nsp::Foo
call.
有一个==
这不适用于::std
命名空间,所以它不会查找::
;一旦发现any ==
即使参数完全不相关,它也会停止查找。它还寻找==
在与参数关联的命名空间中——在本例中::nsp
。但它从来不看::
这里也可以。
将运算符添加到类型时,请始终在该类型的命名空间中定义该运算符。
命名空间可以重新打开。因此,如果您无法控制头文件,您可以使用以下命令创建一个新的头文件==
在里面。这==
必须在每个地方都可见optional<nsp::Foo>::operator==
被调用或者您的程序由于 ODR 违规而格式不正确(在这种情况下,还会生成编译器错误,这对于避免 heizenbug 很有用)。
长版
当您调用运算符(或函数)时,查找遵循几个简单的步骤。
首先,它在本地(在本地命名空间中)查找。如果在那里发现任何东西,搜索就会停止。 (这包括using ns::identifier;
名称注入到命名空间中,但通常不是using namespace foo;
)。即使函数或运算符不适用于相关类型,也会发生这种“停止”;任何==
对于命名空间中的任何类型,都会停止此搜索。
如果找不到匹配项,它将开始查找封闭的命名空间,直到找到函数/运算符,或到达根命名空间。如果有using namespace foo;
声明时,这些命名空间中的函数/运算符被视为位于两个命名空间的“公共父”命名空间中using namespace
位置和正在导入的命名空间。 (所以using namespace std;
in namespace foo
让它看起来像std
is in ::
,不在foo
).
结果会生成一个用于重载解决方案的候选集合。
接下来,完成 ADL(参数相关查找)。检查所有函数/运算符参数的关联命名空间。此外,还会(递归地)检查模板的所有类型参数的关联命名空间。
收集与名称匹配的运算符/函数。对于 ADL,不检查父名称空间。
这两个运算符/函数的集合是重载解析的候选者。
在你的情况下,命名空间在哪里==
被称为是boost
. boost
有很多==
运算符(即使它们不适用),所以所有==
in boost
是候选人。
接下来,我们检查参数的名称空间——nsp::Foo
在这种情况下。我们看看nsp
并看到没有==
.
然后我们对它们运行重载解析。没有候选人工作,你会得到一个编译器错误。
现在,当您移动用户定义的==
into namespace nsp
,然后将其添加到集合中==
在 ADL 步骤中找到。当它匹配时,它就被称为。
超载解决方案(它对候选人的作用)本身就是一个复杂的主题。简而言之,它试图找到涉及最少转换量的重载;如果两种情况彼此完全匹配,则它会优先选择非模板而不是模板,并且优先选择非可变参数而不是可变参数。
“最少转换量”和“精确”中有很多细节可能会误导程序员。最常见的是转换Foo
左值到Foo const&
是一个小量的转换,将其转换为template<class T> T&&
or T&
是没有转换。