提问人:Luchian Grigore 提问时间:10/19/2012 更新时间:10/21/2016 访问量:7254
一元运算符的关联性是否有意义?
Does it make sense for unary operators to be associative?
问:
http://en.cppreference.com/w/cpp/language/operator_precedence 中的C++运算符优先级表(我知道它不是规范的,但标准没有谈论优先级或关联性)将一元运算符标记为右/左关联。
从对另一个问题的讨论中,我留下了疑问。一元运算符的关联性是否有意义?
答:
不确定,但如果以下内容有效,是的。
++i--
但事实并非如此,并抛出错误
lvalue required as increment operand
一元运算符的所有行为只能用优先级来解释。
评论
在一元运算符的情况下,运算符的关联性仅决定了运算符出现在操作数的哪一侧。
评论
它只是从语法中派生出关联性的方式的人工制品。
加法是左关联的原因是,加法表达式的产物之一是加法表达式 + 乘法表达式,加法表达式在左边。因此,当您看到:
a + b + c
这必须等价于 ,因为匹配生产的唯一方法是 with 作为加法表达式和乘法表达式。 它本身是一个加法表达式,但不是乘法表达式,因此如果我们尝试将其作为加法表达式,则与生产不匹配。(a + b) + c
a + b
c
a
b + c
a + b + c
a
如果你以前没有读过,我建议你通读“表达式”一章,忽略语义:只看语法。然后你会看到优先级和关联性是如何由语法定义的。最大的诀窍是,每个“高优先级”类型的表达式都是“低优先级”类型的表达式。因此,每个乘法表达式都是一个加法表达式,但反之则不然,这就是乘法比加法“绑定更紧密”的原因。
前缀一元运算符在语法中定义,例如:unary-expression:++ cast-expression 等,运算符在左边是前缀,右边是后缀。换句话说,我们在左侧“插入括号”表示后缀,在右侧插入括号表示前缀。也就是说,我们可以说后缀运算符的分组是从左到右,前缀运算符的分组是从右到左。事实上,C++标准正是这么说的(C++03中的5.2/1和5.3/1)。将这种一元分组称为“关联性”可能是对术语的滥用,或者至少是一种新的创造。但这不是一个主要的问题,因为必须意味着什么是显而易见的。
二元运算符和一元运算符之间的唯一区别是,如果二元运算符以相反的方向分组,则语法仍然有意义,因此意味着。这将是令人惊讶的,但不会影响语言。对于一元运算符,将 分组为 是令人惊讶的,语言还必须为子表达式提供含义,而目前它没有。函数式语言可以赋予它一个含义:可能意味着由 和 组成的函数,即与 相同的操作,但 C++ 没有组合函数或运算符的概念。C++ 不需要提供该含义的原因是“从右到左分组”。这(因为语法上的大把戏)只是另一种说法,它不是语法正确的表达,所以从来都不是任何东西的子表达。a - b - c
a - (b - c)
!!a
(!!)a
!!
!!
!
!
static_cast<bool>()
!
!!
所以,是的,说前缀运算符从右到左分组,后缀运算符从左到右分组确实是有道理的。但同样“显而易见”的是,它必须是这样的,因为我们对 C++ 语言的其他了解。
顺便说一句,我认为至少从技术上讲,在 C++ 中,postfix 不是一个一元运算符。它是一个后缀运算符。但这并不重要,只是它是标准中的术语,因为显然它是一个运算符,它有一个操作数,所以英语中的“一元”也是如此。++
评论
请考虑以下代码段
int *p;
*p++;
表达式的计算结果可以是(递增 p 指向的对象)或(指向 p 指向的下一个对象)。*p++
(*p)++
*(p++)
由于一元运算符是右关联运算符,因此表达式的计算结果为 。(我在阅读 Kernighan 和 Ritchie 时想到了这一点。*p++
*(p++)
似乎优先级和关联性已更改,后缀的优先级高于取消引用运算符。++
*
根据 C11,上述表达式的计算结果为 。*(p++)
我希望这能更清楚地说明为什么一元运算符具有关联性。
感谢 Lucian Grigore 指出这一点。
评论
上一个:lambda 比较是确定性的吗?
下一个:指针可以有不同的大小吗?[复制]
评论