HC4*_*ica 3 c++ enums namespaces overload-resolution c++11
我今天遇到了一个奇怪的情况,声明一个带有某些参数的已删除运算符改变了看似无关的代码的行为.
我将它减少到以下.从这开始:
namespace N
{
enum E { A, B };
struct C
{
C(E);
private:
C(int);
};
}
N::E operator|(N::E, N::E);
namespace N
{
void Waldo()
{
C(A | B);
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,C有两个构造函数,一个是公共的,另一个是私有的.此代码编译,表明正在选择公共重载,因此表达式A | B具有类型E.反过来,这也意味着,operator|(N::E, N::E)已被匹配(否则A和B将接受隐式转换为整数的类型,A | B会int和私人构造函数相匹配.
到现在为止还挺好.现在我定义一个新的枚举类型F,并删除operator|涉及F:
namespace N
{
enum E { A, B };
struct C
{
C(E);
private:
C(int);
};
}
N::E operator|(N::E, N::E);
namespace N
{
enum F {};
int operator|(F, int) = delete;
void Waldo()
{
C(A | B);
}
}
Run Code Online (Sandbox Code Playgroud)
现在代码没有编译,说这C(int)是私有的.这表明现在A | B有了类型int,这意味着operator|(N::E, N::E)不再匹配.
为什么添加已删除的operator|(F, int)停止operator|(N::E, N::E)匹配?
首先,注意声明为deleted是无关紧要的,因为删除的函数仍然参与重载解析.
现在,重载决议.参看 13.3.1.2/3:
三组候选的功能,指定构件的候选,非成员候选和内置候选,被构造
(没有成员候选者,因为E它不是类类型.)我们知道运算符重载是由非限定查找找到的.所以当我们查阅3.4.1("不合格的查找")时,我们发现了
一旦找到名称的声明,名称查找就会结束.
由于在命名空间中引入了第二个运算符重载N,因此首先找到它,并且名称查找停止.此时,过载集由您int N::operator|(N::F, int)和内置运算符组成.继续在13.3.1.2/6:
重载决策的候选函数集是成员候选者,非成员候选者和内置候选者的联合.
只有内置的是可行的(因为你不能转换E到F隐式),因此选择.