运算符优先级,文档不一致
Operator precedence, inconsistent documentations
我正在刷新我对运算符优先级的记忆,因为我尽量做个聪明人并尽可能避免括号,刷新以下 2 个链接:
我遇到的一个问题是,那两个 "reliable" 文档讲的不是同一件事,我不知道该相信谁了?
例如,Cppreference 表示 throw
关键字与条件运算符在同一组中。 Microsoft 的文档说条件运算符高于 throw
。还有其他区别。
哪个网站是正确的,或者这两个网站在不同方面都是错误的?
TL;DR:Microsoft 文档可能被解释为不太正确,具体取决于您如何看待它们。
您首先要了解的是 C++ 作为一种语言没有 "operator precedence" 规则。 C++有一个语法;正是语法定义了一段特定的 C++ 语法的含义。 C++ 语法告诉你 5 + 3 * 4
应该被认为等同于 5 + (3 * 4)
而不是 (5 + 3) * 4
.
因此,您看到的任何 "operator precedence" 规则只是对C++ grammar around expression parsing 的文本、人类可读的解释。因此,可以想象可能存在两种不同的方式来描述同一语法的行为。
考虑 throw
与 ?:
运算符的具体示例。 Microsoft 站点表示 ?:
的优先级高于 throw
,而 Cppreference 站点表示它们具有相同的优先级。
首先,让我们看一个假设的 C++ 表达式:
throw val ? one : two
根据 Microsoft 的规则,?:
运算符具有更高的优先级,因此将被解析为 throw (val ? one : two)
。根据 Cppreference 的规则,这两个运算符具有相同的优先级。但是,由于它们具有从右到左的关联性,因此 ?:
在子表达式上获得优先权。所以我们有 throw (val ? one : two)
.
所以他们都解决了相同的结果。
但是 C++ 语法是怎么说的呢?好吧,这是语法的相关片段:
throw-expression:
throw assignment-expression(opt)
assignment-expression:
conditional-expression
logical-or-expression assignment-operator initializer-clause
throw-expression
这被解析为一个抛出表达式,其中包含一个 assignment-expression
,其中包含一个 conditional-expression
,这就是我们的 ?:
所在的位置。简而言之,解析器将其解析为 throw (val ? one : two)
.
所以这两个页面是一样的,而且都是正确的。
现在考虑:
val ? throw one : two
这是如何解析的?好吧,要记住 ?:
是一个三元运算符;与大多数其他人不同,它具有三个术语。也就是说,在 : <something>
被解析之前,conditional-expression
本身并未被指定 finished。
因此 throw
与 ?:
的优先级在这种情况下无关紧要。 throw one
在三元运算符内,因为表达式 字面上在 三元运算符内。两家运营商没有竞争。
最后,怎么样:
val ? one : throw two
Microsoft 给予 ?:
更高的优先级。根据微软的文档,优先级"specifies the order of operations in expressions that contain more than one operator"。所以 ?:
先发生。
问题就在这里。 throw
本身实际上是一个语法上合法的表达式(它仅在 catch
子句中有效的 C++,但语法在任何地方都是合法的)。因此,val ? one : throw
可能是一个合法的表达式,这就是 Microsoft 文档的规则似乎要表达的意思。
当然,(val ? one : throw) two
不是合法的表达式,因为 () two
不是合法的 C++ 语法。因此,可以将 Microsoft 的规则解释为这应该是一个编译错误。
但事实并非如此。 C++ 的语法状态:
conditional-expression:
logical-or-expression
logical-or-expression ? expression : assignment-expression
throw two
是用作给定表达式的第三个操作数的完整 assignment-expression
。所以这应该被解析为 val ? one : (throw two)
.
那么 Cppreference 呢?好吧,通过赋予它们从右到左的关联性,throw two
与自身组合在一起。所以应该考虑val ? one : (throw two)
.
我正在刷新我对运算符优先级的记忆,因为我尽量做个聪明人并尽可能避免括号,刷新以下 2 个链接:
我遇到的一个问题是,那两个 "reliable" 文档讲的不是同一件事,我不知道该相信谁了?
例如,Cppreference 表示 throw
关键字与条件运算符在同一组中。 Microsoft 的文档说条件运算符高于 throw
。还有其他区别。
哪个网站是正确的,或者这两个网站在不同方面都是错误的?
TL;DR:Microsoft 文档可能被解释为不太正确,具体取决于您如何看待它们。
您首先要了解的是 C++ 作为一种语言没有 "operator precedence" 规则。 C++有一个语法;正是语法定义了一段特定的 C++ 语法的含义。 C++ 语法告诉你 5 + 3 * 4
应该被认为等同于 5 + (3 * 4)
而不是 (5 + 3) * 4
.
因此,您看到的任何 "operator precedence" 规则只是对C++ grammar around expression parsing 的文本、人类可读的解释。因此,可以想象可能存在两种不同的方式来描述同一语法的行为。
考虑 throw
与 ?:
运算符的具体示例。 Microsoft 站点表示 ?:
的优先级高于 throw
,而 Cppreference 站点表示它们具有相同的优先级。
首先,让我们看一个假设的 C++ 表达式:
throw val ? one : two
根据 Microsoft 的规则,?:
运算符具有更高的优先级,因此将被解析为 throw (val ? one : two)
。根据 Cppreference 的规则,这两个运算符具有相同的优先级。但是,由于它们具有从右到左的关联性,因此 ?:
在子表达式上获得优先权。所以我们有 throw (val ? one : two)
.
所以他们都解决了相同的结果。
但是 C++ 语法是怎么说的呢?好吧,这是语法的相关片段:
throw-expression: throw assignment-expression(opt) assignment-expression: conditional-expression logical-or-expression assignment-operator initializer-clause throw-expression
这被解析为一个抛出表达式,其中包含一个 assignment-expression
,其中包含一个 conditional-expression
,这就是我们的 ?:
所在的位置。简而言之,解析器将其解析为 throw (val ? one : two)
.
所以这两个页面是一样的,而且都是正确的。
现在考虑:
val ? throw one : two
这是如何解析的?好吧,要记住 ?:
是一个三元运算符;与大多数其他人不同,它具有三个术语。也就是说,在 : <something>
被解析之前,conditional-expression
本身并未被指定 finished。
因此 throw
与 ?:
的优先级在这种情况下无关紧要。 throw one
在三元运算符内,因为表达式 字面上在 三元运算符内。两家运营商没有竞争。
最后,怎么样:
val ? one : throw two
Microsoft 给予 ?:
更高的优先级。根据微软的文档,优先级"specifies the order of operations in expressions that contain more than one operator"。所以 ?:
先发生。
问题就在这里。 throw
本身实际上是一个语法上合法的表达式(它仅在 catch
子句中有效的 C++,但语法在任何地方都是合法的)。因此,val ? one : throw
可能是一个合法的表达式,这就是 Microsoft 文档的规则似乎要表达的意思。
当然,(val ? one : throw) two
不是合法的表达式,因为 () two
不是合法的 C++ 语法。因此,可以将 Microsoft 的规则解释为这应该是一个编译错误。
但事实并非如此。 C++ 的语法状态:
conditional-expression: logical-or-expression logical-or-expression ? expression : assignment-expression
throw two
是用作给定表达式的第三个操作数的完整 assignment-expression
。所以这应该被解析为 val ? one : (throw two)
.
那么 Cppreference 呢?好吧,通过赋予它们从右到左的关联性,throw two
与自身组合在一起。所以应该考虑val ? one : (throw two)
.