我的问题是关于静态成员初始值设定项的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;
}
从4.8开始的gcc定义了S范围内的lambda,所以程序输出如下:
Hello from S::<lambda()>
(gcc-4.8.2对__FUNCTION__
&amp; Co宏有不同的定义,但是lambda仍在S
中定义
同时gcc-4.7定义了全局范围内的lambda,因此程序输出
Hello from <lambda()>
可能更新的gcc更符合标准。但是,我想询问标准是否实际指定了这个方面,或者它是否可以依赖于实现。
更新:由于@ 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;
}
答案 0 :(得分:7)
之前已经提出此问题,但我找不到相关的错误报告。这是一个broken link的MSVC错误报告,据称已提交(2015年仍未修复:您可以在rise4fun进行测试)。然而,对于海湾合作委员会来说,它已被固定在4.7到4.8之间。用于支持这个错误的相关标准是:
[C ++ 11,9.4.2 / 2] a。定义中的初始化表达式
static
数据成员属于其类的范围。[C ++ 11,5.1.2 / 2] lambda表达式的评估导致prvalue临时(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?
答案 1 :(得分:4)
我想它应该在课堂范围内。引自cppreference(强调我的):
lambda表达式构造一个未命名的prvalue临时对象 唯一的非命名非联合非聚合类型,称为闭包类型, 在最小的块中声明(出于ADL的目的) 包含lambda的范围,类范围或命名空间范围 表达强>
在S::s_func
的外线定义中,您在遇到S
时遇到S::
的范围。因此,lambda表达式包含在S
的类范围中。由于close类型是S
的成员,因此可以访问S
的私有成员。