【问题标题】:Why Can't Member Variables Be Used Unqualified In A Lambda If Non-Captured Local Variables Exist?如果存在未捕获的局部变量,为什么不能在 Lambda 中使用不合格的成员变量?
【发布时间】:2017-10-20 17:44:55
【问题描述】:

简单示例:

class Foo {
    int x;

    void bar(int x) {
        [this]() -> void {
            x = 6;
        }();
    }
};

这不能在 GCC、Clang、MVC 或 ICC (see it live) 上编译。如果我将void bar(int x) 更改为void bar(int y),或者如果我将x = 6; 更改为this->x = 6;,那么它工作正常。

这对我来说没有意义。来自对 bar 的调用的局部变量 x 故意不在 lambda 中捕获。唯一有意义的xFoo 的成员变量。

问题:这是预期的行为吗?如果是,请解释原因?

【问题讨论】:

  • 也许标签 language-lawyer 可能合适?
  • 编译器失败时会说什么?
  • 在问题中包含相关错误。
  • 在您的情况下,x=6 引用了bar(int x)x。而你只是没有捕捉到它,仅此而已。我的意思是:那么这种歧义被视为错误。但仍然 +1
  • 看来问题的要点是x = 6;中的x是否应该查找bar的参数,或者类成员。我找不到标准涵盖的地方

标签: c++ lambda language-lawyer shadowing


【解决方案1】:

来自cppreference

出于名称查找的目的,确定 这个指针和访问非静态类成员,主体 在上下文中考虑闭包类型的函数调用运算符 的 lambda 表达式。

在方法 bar(int x) 的主体中,标记“x”指的是方法的参数,而不是类的成员。该成员已隐藏。 [注意这当然是糟糕的编码习惯,但并不违法]

如果你说x = 6,你当前有 lambda 定义,你会期望局部变量 x(即方法的传递值参数)被改变,而不是成员 @ 987654324@,对吧?

因此唯一的问题是局部变量能否被 lambda 隐式捕获?我想说编译器很清楚地解释它不能。

cppreference 在此声明中也明确说明了这一点:

如果一个变量没有被捕获,它可以被使用而不被捕获 自动存储持续时间(即它不是局部变量或者它是 静态或线程本地),或者如果它没有在 lambda 的主体中使用。

注意:odr-used 意味着您必须知道变量的地址,而不仅仅是它的值。为变量赋值算作 odr-using 它。

考虑这段代码:

class Foo {
    int george;

    void bar(int washington) {
        int martha = washington;
        washington = 7;
        int jefferson = washington;
        int adams = martha;
        george = 6;
        [this, jefferson]() -> void {
            this->george = 15; // legal because `this` is captured
            jefferson = adams; // legal because jefferson is explicitly
                               // captured, and because adams is not
                               // odr-used, so adams can be captured
                               // implicitly.
            martha = 9; // not legal because it is an odr-use 
                        // of a local variable so martha is not 
                        // implicitly captured.
        }();
    }

【讨论】:

    【解决方案2】:

    你说的错误:

    错误:无法在未指定捕获默认值的 lambda 中隐式捕获变量“x”

    x = 6;

    注意:此处声明的“x” 空栏(int x){ ^ 注意:lambda 表达式从这里开始 这->无效{ ^ 警告:未使用私有字段“x”[-Wunused-private-field] 整数 x;

    这让我发现问题出在变量 x 的定义(或更准确地说,重新定义)上。您在 bar() 之外和作为参数声明它。以下代码已编译给我(使用您显示的实时tool):

    class Foo {
        int x;
    
        void bar() {
            [this]() -> void {
                x = 6;
            }();
        }
    };
    

    希望这会有所帮助。

    【讨论】:

    • 这是真的,但它没有回答问题。删除参数(或更改它,如我所写:void bar(int y))将使其编译 - 但问题是(1)这是故意的而不是错误,(2)如果是这样,为什么 是否选择了这种行为。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多