[expr.unary.op]/9似乎暗示下面的类型A不能应用`operator !()`。但编译器与此不同意。

7

[conv]/4

某些语言结构要求将表达式转换为布尔值。在这种情况下出现的表达式e被称为上下文转换为bool,当且仅当声明bool t(e);对于一些虚构的临时变量t是良好形式的(11.6)。

现在考虑以下代码片段。它无法编译,无论是在clangGCC还是VS中。

struct A{ bool operator!() { return true; } };
int main(){
    A a;
    bool t(a);
}

因此,从[conv]/4我们得出结论,类型A没有被上下文地转换为bool
来自[expr.unary.op]/9
逻辑非运算符!的操作数会被上下文地转换为bool(第7条);如果转换后的操作数为false,则其值为true,否则为false。结果的类型是bool
我理解上面的段落是逻辑非运算符!的操作数必须被上下文地转换为bool。我们刚才已经得出结论,类型A没有被上下文地转换为bool。因此,根据[expr.unary.op]/9,我们可以说以下代码不应该编译通过。但它在clangGCCVS中确实可以通过编译。
struct A{ bool operator!() { return true; } };
int main(){
    A a;
    bool t = !a;
}

我错过了什么?


3
我猜那不是一个逻辑否定运算符,而是成员函数A::operator!。我认为这与operator,相同,即使没有重载,逗号运算符也具有固有含义,但如果提供了重载,则已定义明确。 - Passer By
尝试在第一个示例中将bool t(a);更改为bool t(!a);。这样编译器就能猜测需要应用operator!了。 - Richard Critten
4
当针对未经过载的类型应用运算符时,[Clause [expr]定义了运算符的效果。] - cpplearner
@路人甲 真的吗?好的,谢谢你指出来。 - Rakete1111
1
@PasserBy Jup,我也找不到它。看起来你错了。你需要检查一下你的源代码 :) - Rakete1111
显示剩余2条评论
1个回答

7

[expr]整体适用于内置操作符:

当应用于未重载的类型时,从句子[expr]定义操作符的效果。

[expr.unary.op]中的定义仅是内置operator!的定义。 此外,[over.match.oper]描述了如何查找重载的运算符:

对于一个具有操作数类型其cv-unqualified版本为T1的一元操作符@,将构造三组候选函数,并分别标记为成员候选函数、非成员候选函数和内置候选函数:[...]

对于!a,您会有两个候选项:重载的A::operator!()[over.built]中定义的内置候选项。

There also exist candidate operator functions of the form

bool operator!(bool);
为了使内置的函数被重载解析选择,您的参数建议将类型转换为bool。然而,这个候选项不可行 - 但是重载成员运算符是可行的。

T.C.像往常一样掌握了局面,指出cwg问题1919,该问题表明一个上下文可转换为bool的类型仍不应使用内置的operator!,由于措辞问题。虽然,gcc和clang都允许它(这可能是我们所有人想要发生的事情)。


1
@T.C. 你真是让人惊叹。此外,Johannes 显然已经提交了每一个核心问题。 - Barry

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接