使用带有默认情况和lambda函数的switch语句时出现gcc错误

Moh*_* Li 4 c++ lambda gcc switch-statement

我不明白为什么这个代码

#include <iostream>

class A {
    public:


    void foo(){
        char g = 'm';
        switch(g){
            case 'g':
                auto f = [](){std::printf("hello world\n");};
                f();
                break;
//            default:
//                std::printf("go to hell\n");
//                break;
        }
    };
};



int main(int iargc, char *iargv[]){
    A a;
    a.foo();
}
Run Code Online (Sandbox Code Playgroud)

编译(并且工作)很好,而在取消注释默认语句时

#include <iostream>

class A {
    public:


    void foo(){
        char g = 'm';
        switch(g){
            case 'g':
                auto f = [](){std::printf("hello world\n");};
                f();
                break;
            default:
                std::printf("go to hell\n");
                break;
        }
    };
};



int main(int iargc, char *iargv[]){
    A a;
    a.foo();
}
Run Code Online (Sandbox Code Playgroud)

给我以下错误消息

test.cpp:15:13: error: jump to case label [-fpermissive]
         default:
         ^
test.cpp:12:22: error:   crosses initialization of ‘A::foo()::__lambda0 f’
             auto f = [](){std::printf("hello world\n");};
Run Code Online (Sandbox Code Playgroud)

如果我注释掉lambda函数,我可以使用默认语句.

我使用的是gcc 4.8.5.

Joh*_*nck 7

你需要将你的case 'g'身体包裹在牙套中.这不是因为lambda本身,而是由于在case语句中创建了任何新变量.

没有默认值,我认为它不会抱怨,因为只有一个地方执行可以流动.但是默认情况下没有大括号,你就会遇到问题,因为f扩展到default代码的范围却不会在那里进行初始化.

  • _"但是由于在case语句中创建了任何新变量."_不是任何变量,只有非标量类型的非变量构造函数或非平凡的析构函数,并且具有初始化程序.(有关准确的规则,请参阅我的答案). (3认同)

Jon*_*ely 6

错误消息可以准确地告诉您问题所在.跳转到default标签的位置f从不在范围内的点到其在范围内的点,跳过其初始化.

该标准的相关规则是:

6.7声明声明[stmt.dcl]

可以转换为块,但不能以初始化绕过声明的方式.从具有自动存储持续时间的变量不在范围内的点跳转到其在范围内的点的程序是不正确的,除非该变量具有标量类型,具有普通默认构造函数的类类型和普通的析构函数,这些类型之一的cv限定版本,或者前面类型之一的数组,并且在没有初始值设定项的情况下声明(8.6).

如果只有一个case用于切换,则无法跳过初始化,因为您可以输入switch语句的唯一位置是第一个case标签,它不会错过初始化.如果你没有绕过变量的初始化那么没有问题.

你没有得到类型之类的错误,double或者int因为它们是标量类型(因此如果你跳过它们的初始化它们在范围内,但未初始化).由lambda创建的闭包类型不是标量类型,并且在没有初始化程序的情况下不会声明.