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

ima*_*ett 6 c++ attributes switch-statement branch-prediction c++20

C++20 具有指导代码生成的方便[[likely]]/[[unlikely]]属性。例如,您可以指定一个分支可能被以下人员采用:

if (b) [[likely]] { /*...*/ }
Run Code Online (Sandbox Code Playgroud)

同样,可以在switchstatements 中使用这些属性。. . 不知何故? 文档建议使用以下示例(稍微格式化):

if (b) [[likely]] { /*...*/ }
Run Code Online (Sandbox Code Playgroud)

其含义显然是[[likely]]/[[unlikely]]case语句之前。互联网似乎几乎普遍宣传这种用法。

但是,请考虑以下类似的代码(我所做的只是将 the[[likely]]移到 other case):

switch (i) {
    case 1:
        [[fallthrough]];
    [[likely]] case 2:
        return 1;
}
Run Code Online (Sandbox Code Playgroud)

这无法在 clang 上编译!虽然这可能与编译器错误有关[[fallthrough]],但它让我查看了标准。在相关的标准有如下的例子(见§VII):

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

switch (i) {
    [[likely]] case 1:
        [[fallthrough]];
    case 2:
        return 1;
}
Run Code Online (Sandbox Code Playgroud)

也就是说,该属性出现案例标签之后,而不是之前。

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

Sto*_*ica 4

这两个示例都是有效的,并且 Clang 表现出了一个错误。C++20 最新标准草案中的相关措辞是

[dcl.attr.可能性]

1属性标记likelyunlikely可以应用于标签或语句。

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

[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
Run Code Online (Sandbox Code Playgroud)

[stmt.标签]

labeled-statement:
  attribute-specifier-seq identifier : statement
  attribute-specifier-seq case constant-expression : statement
  attribute-specifier-seq default : statement
Run Code Online (Sandbox Code Playgroud)

switch (i) {
    case 1:
        [[fallthrough]];
    [[likely]] case 2:
        return 1;
}
Run Code Online (Sandbox Code Playgroud)

该属性适用case 2:

switch (a) {
    case 1: [[likely]]
        foo();
        break;
    //...
}
Run Code Online (Sandbox Code Playgroud)

它适用于声明foo();