一元运算符的关联性是否有意义?

Does it make sense for unary operators to be associative?

提问人:Luchian Grigore 提问时间:10/19/2012 更新时间:10/21/2016 访问量:7254

问:

http://en.cppreference.com/w/cpp/language/operator_precedence 中的C++运算符优先级表(我知道它不是规范的,但标准没有谈论优先级或关联性)将一元运算符标记为右/左关联。

从对另一个问题的讨论中,我留下了疑问。一元运算符的关联性是否有意义?

C++ 元运算符 关联性

评论

0赞 SergeyS 12/30/2012
请看我的答案 这里 (stackoverflow.com/a/14084830/1740808) 以及具有左关联前缀运算符的连字符语言示例

答:

1赞 Anirudh Ramanathan 10/19/2012 #1

不确定,但如果以下内容有效,是的。

++i--

但事实并非如此,并抛出错误

lvalue required as increment operand

一元运算符的所有行为只能用优先级来解释。

评论

1赞 Seth Carnegie 10/19/2012
不可以,后缀的优先级高于前缀。
2赞 Seth Carnegie 10/19/2012 #2

在一元运算符的情况下,运算符的关联性仅决定了运算符出现在操作数的哪一侧。

评论

2赞 Seth Carnegie 10/19/2012
@LuchianGrigore,它们是不同的运营商。
0赞 Luchian Grigore 10/19/2012
啊,是的,它们出现了 2 次 - 前缀前的后缀。
0赞 Luchian Grigore 10/19/2012
所以,最重要的是,它们是联想的,只是与其他的在意义上不同?
1赞 Seth Carnegie 10/19/2012
@LuchianGrigore是的,因为它们不能像二进制运算符那样具有相同的歧义,但您必须弄清楚当一元运算符位于两个可能的操作数之间时,它适用于哪个操作数。
0赞 Luchian Grigore 10/19/2012
你能举一个模棱两可的例子吗?
12赞 Steve Jessop 10/19/2012 #3

它只是从语法中派生出关联性的方式的人工制品。

加法是左关联的原因是,加法表达式的产物之一是表达式 + 乘法表达式,加法表达式在左边。因此,当您看到:

a + b + c

这必须等价于 ,因为匹配生产的唯一方法是 with 作为加法表达式和乘法表达式。 它本身是一个加法表达式,但不是乘法表达式,因此如果我们尝试将其作为加法表达式,则与生产不匹配。(a + b) + ca + bcab + ca + b + ca

如果你以前没有读过,我建议你通读“表达式”一章,忽略语义:只看语法。然后你会看到优先级和关联性是如何由语法定义的。最大的诀窍是,每个“高优先级”类型的表达式都是“低优先级”类型的表达式。因此,每个乘法表达式都是一个加法表达式,但反之则不然,这就是法比加法“绑定更紧密”的原因。

前缀一元运算符在语法中定义,例如:unary-expression:++ cast-expression 等,运算符在左边是前缀,右边是后缀。换句话说,我们在左侧“插入括号”表示后缀,在右侧插入括号表示前缀。也就是说,我们可以说后缀运算符的分组是从左到右,前缀运算符的分组是从右到左。事实上,C++标准正是这么说的(C++03中的5.2/1和5.3/1)。将这种一元分组称为“关联性”可能是对术语的滥用,或者至少是一种新的创造。但这不是一个主要的问题,因为必须意味着什么是显而易见的。

二元运算符和一元运算符之间的唯一区别是,如果二元运算符以相反的方向分组,则语法仍然有意义,因此意味着。这将是令人惊讶的,但不会影响语言。对于一元运算符,将 分组为 是令人惊讶的,语言还必须为子表达式提供含义,而目前它没有。函数式语言可以赋予它一个含义:可能意味着由 和 组成的函数,即与 相同的操作,但 C++ 没有组合函数或运算符的概念。C++ 不需要提供该含义的原因是“从右到左分组”。这(因为语法上的大把戏)只是另一种说法,它不是语法正确的表达,所以从来都不是任何东西的子表达。a - b - ca - (b - c)!!a(!!)a!!!!!!static_cast<bool>()!!!

所以,是的,说前缀运算符从右到左分组,后缀运算符从左到右分组确实是有道理的。但同样“显而易见”的是,它必须是这样的,因为我们对 C++ 语言的其他了解。

顺便说一句,我认为至少从技术上讲,在 C++ 中,postfix 不是一个一元运算符。它是一个后缀运算符。但这并不重要,只是它是标准中的术语,因为显然它是一个运算符,它有一个操作数,所以英语中的“一元”也是如此。++

评论

0赞 SergeyS 12/30/2012
请参阅我的答案 这里 (stackoverflow.com/a/14084830/1740808) 以及具有左关联前缀运算符的连字符语言示例
2赞 Shekhar Bhandakkar 10/12/2016 #4

请考虑以下代码段

int *p;
*p++;

表达式的计算结果可以是(递增 p 指向的对象)或(指向 p 指向的下一个对象)。*p++(*p)++*(p++)

由于一元运算符是右关联运算符,因此表达式的计算结果为 。(我在阅读 Kernighan 和 Ritchie 时想到了这一点。*p++*(p++)

似乎优先级和关联性已更改,后缀的优先级高于取消引用运算符。++*

根据 C11,上述表达式的计算结果为 。*(p++)

我希望这能更清楚地说明为什么一元运算符具有关联性。

感谢 Lucian Grigore 指出这一点。

评论

0赞 Luchian Grigore 10/21/2016
Postfix 是从左到右的关联 - en.cppreference.com/w/cpp/language/operator_precedence,所以这个论点不会成立。此外,在这种情况下,评估的顺序由优先级决定,因为后增量的优先级高于取消引用的优先级。
0赞 Shekhar Bhandakkar 10/21/2016
感谢您的见解。
0赞 12/22/2019
我认为一元运算符根本没有关联性,因为不允许链接同一个运算符,所以应该优先而不是关联性来解决——正如你所说,他们现在已经理解了。