[英]Unrelated deleted operator changes behaviour of overload resolution
I came across a strange situation today, where declaring a deleted operator with certain arguments changed the behaviour of seemingly unrelated code. 我今天遇到了一个奇怪的情况,声明一个带有某些参数的已删除运算符改变了看似无关的代码的行为。
I reduced it to the following. 我将它减少到以下。 Start with this:
从这开始:
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);
}
}
Notice that C has two constructors, a public one and a private one. 请注意,C有两个构造函数,一个是公共的,另一个是私有的。 This code compiles, indicating that the public overload is being chosen, so the expression
A | B
此代码编译,表明正在选择公共重载,因此表达式为
A | B
A | B
has type E
. A | B
有E
型。 In turn this means that the operator|(N::E, N::E)
has been matched (otherwise A
and B
would undergo implicit conversion to integers, the type of A | B
would be int
, and the private constructor would be matched. 反过来,这意味着
operator|(N::E, N::E)
已匹配(否则A
和B
将进行隐式转换为整数, A | B
的类型将为int
,私有构造函数将为匹配。
So far so good. 到现在为止还挺好。 Now I define a new enumeration type
F
, and a deleted operator|
现在我定义一个新的枚举类型
F
和一个删除的operator|
that involves F: 涉及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);
}
}
Now the code doesn't compile, saying that C(int)
is private. 现在代码没有编译,说
C(int)
是私有的。 This indicates that now A | B
这表明现在是
A | B
A | B
has type int
, which means operator|(N::E, N::E)
is no longer being matched. A | B
类型为int
,表示operator|(N::E, N::E)
不再匹配。
Why did the addition of the deleted operator|(F, int)
stop operator|(N::E, N::E)
from being matched? 为什么添加删除的
operator|(F, int)
会使operator|(F, int)
operator|(N::E, N::E)
停止匹配?
First off, note that being declared as delete
d is irrelevant, since deleted functions still take part in overload resolution. 首先,注意声明为
delete
d是无关紧要的,因为删除的函数仍然参与重载解析。
Now, on to overload resolution. 现在,重载决议。 Cf.
参看 13.3.1.2/3:
13.3.1.2/3:
three sets of candidate functions, designated member candidates , nonmember candidates and built-in candidates , are constructed
构建了三套候选职能,指定成员候选人 , 非成员候选人和内置候选人
(There are no member candidates, since E
is not a class type.) We know from that the operator overload is found by unqualified lookup . (没有成员候选者,因为
E
不是类类型。)我们知道运算符重载是由非限定查找找到的。 So when we consult 3.4.1 ("Unqualified lookup"), we find that 所以当我们查阅3.4.1(“不合格的查找”)时,我们发现了这一点
name lookup ends as soon as a declaration is found for the name.
一旦找到名称的声明,名称查找就会结束。
Since you introduce the second operator overload within the namespace N
, it is found first, and name lookup stops. 由于您在命名空间
N
引入了第二个运算符重载,因此首先找到它,并且名称查找停止。 At this point, the overload set consists of your int N::operator|(N::F, int)
and the built-in operators. 此时,重载集由
int N::operator|(N::F, int)
和内置运算符组成。 Continuing in 13.3.1.2/6: 继续在13.3.1.2/6:
The set of candidate functions for overload resolution is the union of the member candidates, the non-member candidates, and the built-in candidates.
重载决策的候选函数集是成员候选者,非成员候选者和内置候选者的联合。
Only the builtin is viable (since you cannot convert E
to F
implicitly), and thus it is chosen. 只有内置是可行的(因为你不能隐含地将
E
转换为F
),因此它被选中。
The solution to your problem is simple. 解决问题的方法很简单。
Put your operator|
把你的
operator|
in the same namespace as the type. 在与类型相同的命名空间中。 Now, ADL (argument dependent lookup) kicks in, and it is found even if there is the unrelated
operator|
现在,ADL(参数依赖查找)启动, 即使存在不相关的
operator|
也可以找到它 also visible. 也可见。
Live example . 实例 。 Note that
N::operator|
注意
N::operator|
is found despite the |
发现尽管
|
being used in namespace Z
. 在
namespace Z
。
The proper place to overload free operators for a type is the namespace
that the type lives in, not the global namespace. 为类型重载自由运算符的适当位置是类型所在的
namespace
,而不是全局命名空间。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.