为啥静态初始化程序中的 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 foo
的private
成员,因为它是在class foo
的static
成员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 中类的私有成员?的主要内容,如果未能解决你的问题,请参考以下文章