简体   繁体   English

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

[英]gcc error when using a switch statement with a default case and a lambda function

I do not understand why this code 我不明白为什么这个代码

#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();
}

compiles (and works) fine, whereas when uncommenting the default 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();
}

gives me the following error message 给我以下错误消息

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");};

I can use a default statement, if I comment out the lambda function. 如果我注释掉lambda函数,我可以使用默认语句。

I am using gcc 4.8.5. 我使用的是gcc 4.8.5。

You need to enclose your case 'g' body in braces. 你需要将你的case 'g'身体括在大括号中。 This is not because of the lambda per se, but due to the creation of any new variable in a case statement. 这不是因为lambda本身,而是由于在case语句中创建了任何新变量。

Without the default I suppose it doesn't complain because there's only one place the execution can flow. 如果没有默认值,我认为它不会抱怨,因为只有一个地方可以执行。 But with default and no braces, you have a problem because the scope of f extends to the default code but it won't be initialized there. 但是默认情况下没有大括号,你会遇到问题,因为f的范围扩展到default代码,但不会在那里初始化。

The error message tells you exactly what the problem is. 错误消息可以准确地告诉您问题所在。 Jumping to the default label goes from a point where f is not in scope to a point where it is in scope, skipping its initialization. 跳转到default标签从f不在范围内的点到其在范围内的点,跳过其初始化。

The relevant rule from the standard is: 该标准的相关规则是:

6.7 Declaration statement [stmt.dcl] 6.7声明声明[stmt.dcl]

It is possible to transfer into a block, but not in a way that bypasses declarations with initialization. 可以转换为块,但不能以初始化绕过声明的方式。 A program that jumps from a point where a variable with automatic storage duration is not in scope to a point where it is in scope is ill-formed unless the variable has scalar type, class type with a trivial default constructor and a trivial destructor, a cv-qualified version of one of these types, or an array of one of the preceding types and is declared without an initializer (8.6). 从具有自动存储持续时间的变量不在范围内的点跳转到其在范围内的点的程序是不正确的,除非变量具有标量类型,具有普通默认构造函数的类类型和普通的析构函数,这些类型之一的cv限定版本,或者前面类型之一的数组,并且在没有初始值设定项的情况下声明(8.6)。

When you only have one case for the switch there is no way to jump over the initialization, because the only place you can enter the switch statement is at the first case label, which doesn't miss out the initialization. 如果只有一个用于交换机的case ,则无法跳过初始化,因为您可以输入switch语句的唯一位置是第一个case标签,它不会错过初始化。 If you don't bypass the initialization of the variable then there's no problem. 如果你没有绕过变量的初始化那么没有问题。

You don't get the error for types like double or int because they are scalar types (so if you jump over their initialization they are in scope, but uninitialized). 你没有得到像doubleint这样的类型的错误,因为它们是标量类型(所以如果你跳过它们的初始化它们在范围内,但未初始化)。 The closure type created by the lambda is not a scalar type, and is not declared without an initializer. 由lambda创建的闭包类型不是标量类型,并且在没有初始化程序的情况下不会声明。

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

A switch transfers control to one of it's labels. switch将控制权转移到其中一个标签上。 All these labels are in the single block introduced by the switch statement. 所有这些标签都在switch语句引入的单个块中。

The standard (N4296 §6.7/3) says (emphasis mine): 标准(N4296§6.7/ 3)说(强调我的):

It is possible to transfer [control] into a block, but not in a way that bypasses declarations with initialization . 可以将[control]转换为块,但不能以初始化绕过声明的方式 A program that jumps from a point where a variable with automatic storage duration is not in scope to a point where it is in scope is ill-formed unless the variable has scalar type, class type with a trivial default constructor and a trivial destructor, a cv-qualified version of one of these types, or an array of one of the preceding types and is declared without an initializer. 从具有自动存储持续时间的变量不在范围内的点跳转到其在范围内的点的程序是不正确的, 除非变量具有标量类型,具有普通默认构造函数的类类型和普通的析构函数,这些类型之一的cv限定版本,或者前面类型之一的数组,并且在没有初始化程序的情况下声明。

Thus, because it is possible to transfer control directly to the default label, past the declaration and initialization of the lambda f (which is not trivially constructible), your program is ill-formed and is rightfully rejected by the compiler. 因此,因为可以直接将控制转移到default标签,通过lambda f的声明和初始化(这不是简单的可构造的),你的程序是不正确的,并且被编译器正确地拒绝。

wrap your code between braces or it is considered as the same block. 将您的代码包装在大括号之间,或者它被视为同一个块。

Jumping to default skips variable declaration. 跳转到默认值会跳过变量声明。

case 'g':
    {
                auto f = [](){std::printf("hello world\n");};
                f();
                break;
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM