在 `switch` 语句中正确使用 C++20 `[[likely]]`/`[[unlikely]]`

问题描述 投票:0回答:1

C++20 有方便的

[[likely]]
/
[[unlikely]]
属性来指导代码生成。 例如,您可以指定一个分支可能被采用:

if (b) [[likely]] { /*...*/ }

同样,可以在

switch
语句中使用这些属性。 。 。不知何故? 文档建议使用以下示例(略有格式):

switch (i) {
    case 1:
        [[fallthrough]];
    [[likely]] case 2:
        return 1;
}

这显然意味着

[[likely]]
/
[[unlikely]]
位于
case
语句之前。 互联网似乎几乎普遍传播这种用法。

但是,请考虑以下类似的代码(我所做的只是将

[[likely]]
移动到另一个
case
):

switch (i) {
    [[likely]] case 1:
        [[fallthrough]];
    case 2:
        return 1;
}

这无法在 clang 上编译! 虽然这可能与 [[fallthrough]]

 的编译器错误有关,但它让我开始研究标准。  相关标准有以下示例(参见§VII):

鼓励实现针对正在执行的情况进行优化(例如,以下代码中的值为 1):

switch (a) { case 1: [[likely]] foo(); break; //... }
也就是说,属性出现在案例标签

之后,而不是之前。

所以。 。 。是哪一个? 顺便说一句,我希望该标准是正确的,但这实际上是一个提案,而不是真正的标准 AFAICT——它可能已经被改变了。 而且,如果不出意外的话,我希望文档至少在基本语法方面是正确的——除了它甚至无法编译。

c++ attributes switch-statement c++20 branch-prediction
1个回答
5
投票
两个示例都是有效的,并且 Clang 存在错误。 C++20 最新标准草案中的相关措辞是

[dcl.attr.可能性]

1 属性标记 likely

unlikely
 可以应用于标签或语句。

语句和标记语句的相关语法产生式在适当的位置具有属性说明符序列。

[stmt.pre]

statement: labeled-statement attribute-specifier-seq expression-statement attribute-specifier-seq compound-statement attribute-specifier-seq selection-statement attribute-specifier-seq iteration-statement attribute-specifier-seq jump-statement declaration-statement attribute-specifier-seq try-block

[stmt.标签]

labeled-statement: attribute-specifier-seq identifier : statement attribute-specifier-seq case constant-expression : statement attribute-specifier-seq default : statement

switch (i) { case 1: [[fallthrough]]; [[likely]] case 2: return 1; }
该属性适用于 

case 2:

 而适用于 

switch (a) { case 1: [[likely]] foo(); break; //... }
它适用于声明

foo();

© www.soinside.com 2019 - 2024. All rights reserved.