静态成员初始化器的Lambda作用域

lambda scope for static members initializer

本文关键字:Lambda 作用域 初始化 静态成员      更新时间:2023-10-16

我的问题是关于静态成员初始化式的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__ &但是,lambda仍然在S

中定义。

同时gcc-4.7在全局作用域中定义了lambda,因此程序输出

Hello from <lambda()>

可能更新的gcc更符合标准。然而,我想问的是,标准是否确实规定了这方面,或者它可以依赖于实现。

Update: as @user5434961建议所有类似__FUNCTION__的宏都依赖于实现,因此最好在符合标准的测试中避免使用它们。因此,如果编译器在S范围内定义了这样的lambdas并中断编译,则可以编译以下示例:

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

这个问题之前已经提出,但我找不到相关的错误报告。这里是一个MSVC错误报告的链接,据说是提交的(它在2015年仍然没有修复:你可以在rise4fun上测试它)。然而,它已经在GCC的4.7和4.8之间修复了。用于将其作为bug进行备份的相关标准是:

[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表达式。

以前

为什么静态初始化器中的lambda不能访问vc++ 2013中类的私有成员?

c++ 11 lambda可以访问我的私有成员。为什么?

为什么不能在lambda中使用私有方法?

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

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

S::s_func的out- line定义中,遇到S::的时间进入S的作用域。因此,lambda表达式包含在S的类作用域中。由于close类型是S的成员,所以授予S的private成员访问权限。