为啥静态初始化程序中的 lambda 无法访问 VC++2013 中类的私有成员?

Posted

技术标签:

【中文标题】为啥静态初始化程序中的 lambda 无法访问 VC++2013 中类的私有成员?【英文标题】:Why lambda in static initializer can't access private members of class in VC++2013?为什么静态初始化程序中的 lambda 无法访问 VC++2013 中类的私有成员? 【发布时间】:2014-08-08 00:23:21 【问题描述】:

考虑以下代码:

#include <iostream>

class foo 
  int var = 99;
public:
  static int const i;
;

int const foo::i = [&]  return foo().var; ();

auto main() -> int 
  std::cout << foo::i << std::endl;
  return 0;

考虑标准§ 9.4.2/2 静态数据成员 [class.static.data]:

中的初始化表达式 static 数据成员的定义在其类的范围内。

§ 5.1.2/2&3 Lambda 表达式 [expr.prim.lambda]:

2 对 lambda 表达式的求值会产生一个临时纯右值 (12.2)。这个临时对象称为闭包对象。 lambda 表达式不应出现在未计算的操作数中(第 5 条)。 [注意:闭包对象的行为类似于函数对象(20.9)。-结束注释]

3 lambda 表达式的类型(也是闭包对象的类型)是唯一的、未命名的非联合类类型——称为闭包类型——其属性如下所述。此类类型不是聚合 (8.5.1)。闭包类型在包含相应 lambda 表达式的最小块作用域、类作用域或命名空间作用域中声明。

我们最终得出结论,表达式中的 lambda:

int const foo::i = [&]  return foo().var; ();

可以正确访问class fooprivate 成员,因为它是在class foostatic 成员i 的初始化表达式中声明和定义的,因此它的范围是class foo 的范围.

代码在GCC v4.8 和Clang v3.4 中编译并运行良好,但在VC++2013 中编译失败,产生编译器错误:

错误 C2248:“foo::var”:无法访问在“foo”类中声明的私有成员

问题:

上面记录的 VC++2013 行为是否是一个错误,或者它是特定 VC++2013 行为的属性,可以通过更改特定的编译器设置来改变?

【问题讨论】:

这看起来很熟悉,实际上是一个错误。 两天前没有关于这个的问题吗? @Praetorian:昨天有this,OP 回答了。这个问题是关于为什么/是否 VS 不合规。 Aghaghaghaghaga @40two stop hindering my search efforts! 以为我终于有了它 @Praetorian “如果有疑问,VS 有问题。”哈哈 【参考方案1】:

这是截至 2017 年 Visual Studios 的错误,在 Visual Studio 2019 中已修复。演示:https://gcc.godbolt.org/z/4564EKbEr

至于

int const foo::i = [&]  return foo().var; ();

非本地 lambda 表达式不能有默认捕获,所以我在演示中更改了它。

但正如我的同事指出的那样,在最新的 Visual Studio for member templates 中仍然存在相同的错误:

#include <iostream>

class foo 
  int var = 99;
public:
  template<class>
  static int const i;
;

template<class>
int const foo::i = []  return foo().var; (); // fails in MSVC

auto main() -> int 
  std::cout << foo::i<int> << std::endl;
  return 0;

演示:https://gcc.godbolt.org/z/hPvoYY3f5

【讨论】:

以上是关于为啥静态初始化程序中的 lambda 无法访问 VC++2013 中类的私有成员?的主要内容,如果未能解决你的问题,请参考以下文章

为啥会出现此错误:无法在初始化程序中访问实例成员'*'。”?

为啥lambda中的变量无法调用函数[关闭]

从 VPC 中的 Lambda 访问 AWS S3

为啥我无法在 C++ 中初始化静态字段 [重复]

python 为啥要使用静态方法

java调用同一个类中的方法为啥要将方法申明成静态?