在 if. 中嵌入案例标签.否则声明

Embedding a case label in an if...else statement

本文关键字:标签 声明 案例 if      更新时间:2023-10-16

G++ 接受这段代码,它的行为符合我的预期:

#include <cassert>
void example (int value, bool condition) {
  switch (value) {
  case 0:
    if (condition) {
  case 1:
      assert(condition || value == 1);
    } else {
      assert(!condition && value == 0);
    }
    assert(value == 0 || value == 1);
  }
}
int main () {
  example(0, false);
  example(1, false);
  example(0, true);
  example(1, true);
}

也许这是一个愚蠢的基本问题,但是,撇开代码气味不谈,在if...else块中放置case标签是否有效C++,并且所有行为良好的编译器都会正确生成代码,这些代码在通过case 1输入时会跳过else块?

就C++而言(草案N3936):

  • 大小写和默认标签本身不会改变控制流,控制流在此类标签之间不受阻碍地继续
  • 通常,作为开关主题的子语句是复合语句,
  • 大小写和默认标签显示在(复合)子语句中包含的顶级语句上,但这不是必需的。(§ 6.4.2 - 6)
  • 可以转移到块中,但不能绕过初始化声明的方式。(§ 6.7 - 3)

你正在做的事情在技术上是可以的,当然这并不意味着你应该这样做。

你正在做的是完全标准的C++代码,尽管我认为它不是特别容易阅读或维护。如果我们查看6.4选择语句C++标准部分的草案,则 switch 语句的语法如下:

switch ( condition ) statement

语句包括标签、if、while、for 等和第 6.4.2switch 语句不会设置任何限制,这些限制会排除您正在显示的代码。

案例标签就像与 goto 一起使用的标签一样,这在第 6.1 标记语句一节中介绍,但它们仅限于在 switch 语句中使用:

案例标签和默认标签只出现在 switch 语句中。

6.7 节说我们可以转移到一个块中,给定一些限制,例如不绕过带有初始化的声明:

可以转移到块中,但不能绕过初始化声明的方式。从具有自动存储持续时间的变量不在作用域中的点跳转到它在作用域中的点跳转87 的程序格式不正确,除非该变量具有标量类型、具有普通默认构造函数和普通析构函数的类类型、这些类型之一的 cv 限定版本或上述类型之一的数组,并且声明时没有初始值设定项 (8.5)。

脚注87说:

在这方面,从开关语句的条件到案例标签的转换被认为是一个跳跃。

也许,switch 语句最著名和最奇怪的用途之一是 Daff 的设备,它有一个嵌入式while循环:

void send( int *to, const int *from, int  count)
{
        int n = (count + 7) / 8;
        switch(count % 8) 
        {
            case 0: do {    *to = *from++;   // <- Scope start
            case 7:         *to = *from++;
            case 6:         *to = *from++;
            case 5:         *to = *from++;
            case 4:         *to = *from++;
            case 3:         *to = *from++;
            case 2:         *to = *from++;
            case 1:         *to = *from++;
                        } while(--n > 0);    // <- Scope end
        }
}