【问题标题】:lambda scope for static members initializer静态成员初始化器的 lambda 范围
【发布时间】:2016-01-09 12:26:09
【问题描述】:

我的问题是关于静态成员初始值设定项的 lambda 范围。考虑以下测试:

#include <functional>
#include <iostream>

struct S {
    static const std::function<void(void)> s_func;
};

const std::function<void(void)> S::s_func = []() {
    std::cout << "Hello from " << __PRETTY_FUNCTION__ << std::endl;
};

int main(void) {
    S::s_func();
    return 0;
}

gcc 从 4.8 开始定义了 S 范围内的 lambda,所以程序输出如下:

Hello from S::<lambda()>

(gcc-4.8.2 对__FUNCTION__ & Co 宏有不同的定义,但是 lambda 仍然在 S 中定义)

同时 gcc-4.7 在全局范围内定义了 lambda,所以程序输出

Hello from <lambda()>

可能较新的 gcc 更符合标准。但是我想问一下标准是否真的指定了这个方面,或者它可以是依赖于实现的。

更新:正如@user5434961 所建议的,所有__FUNCTION__-alike 宏都依赖于实现,因此最好在符合标准的测试中避免使用它们。因此,如果编译器在 S 范围内定义了此类 lambda,则可以编译以下示例,否则会中断编译:

#include <functional>
#include <iostream>

struct S {
    static const std::function<void(void)> s_func;
private:
    static const int s_field;
};

const std::function<void(void)> S::s_func = []() {
    std::cout << "Hello from S::s_func. S::s_field = " << S::s_field << std::endl;
};

const int S::s_field = 1;

int main(void) {
    S::s_func();
    return 0;
}

【问题讨论】:

  • 我猜你应该在更新的示例中将S::s_field 更改为s_field?否则,我认为它总是可以编译任何范围。
  • 好吧,由于S::s_field 是私有的,因此无法从全局范围访问它,因此代码确实会破坏 GCC-4.7 上的编译
  • 是的,是的。我忽略了私人的事情。

标签: c++ c++11 lambda


【解决方案1】:

这个问题之前已经提出过,但我找不到相关的错误报告。这是一个 broken link 用于据称已提交的 MSVC 错误报告(它在 2015 年仍未修复:您可以在 rise4fun 对其进行测试)。然而,对于 GCC,它已被固定在 4.7 和 4.8 之间。用于将其作为错误支持的相关标准是:

[C++11, 9.4.2/2] 定义中的初始化表达式 static 数据成员在其类的范围内。

[C++11, 5.1.2/2] 对 lambda 表达式的求值会产生一个临时纯右值 (12.2)。这个临时对象称为闭包对象。 lambda 表达式不得出现在未计算的操作数中(第 5 条)。

[C++11, 5.1.2/3] lambda 表达式的类型(也是 闭包对象的类型)是唯一的、未命名的非联合类类型 — 称为闭包类型 — 其属性如下所述。这 类类型不是聚合(8.5.1)。声明了闭包类型 在最小的块范围、类范围或命名空间范围内 包含相应的 lambda 表达式。

以前

Why lambda in static initializer can't access private members of class in VC++2013?

C++11 lambdas can access my private members. Why?

Why is it not possible to use private method in a lambda?

【讨论】:

    【解决方案2】:

    我想它应该在类范围内。引用自cppreference(强调我的):

    lambda 表达式构造一个未命名的纯右值临时对象 唯一的未命名非联合非聚合类型,称为闭包类型, 在最小块中声明(为了 ADL 的目的) 包含 lambda 的作用域、类作用域或命名空间作用域 表达

    S::s_func 的外联定义中,您在遇到S:: 的时间进入S 的范围。因此,lambda 表达式包含在S 的类范围内。由于 close 类型是 S 的成员,因此授予对 S 私有成员的访问权限。

    【讨论】:

    • 感谢您和@user5434961 提供同样有用的答案。我将他的答案标记为已接受,因为它比你的早一点。
    • @user3159253 不客气 :) user5434961 的回答比我的引用标准文档要好。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-04-21
    • 2011-07-18
    • 2013-07-21
    • 1970-01-01
    • 1970-01-01
    • 2015-05-18
    • 1970-01-01
    相关资源
    最近更新 更多