静态成员初始值设定项的lambda范围

时间:2015-10-12 05:53:28

标签: c++ c++11 lambda

我的问题是关于静态成员初始值设定项的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;
}

2 个答案:

答案 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?

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

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

答案 1 :(得分:4)

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

  

lambda表达式构造一个未命名的prvalue临时对象   唯一的非命名非联合非聚合类型,称为闭包类型,   在最小的块中声明(出于ADL的目的)   包含lambda的范围,类范围或命名空间范围   表达

S::s_func的外线定义中,您在遇到S时遇到S::的范围。因此,lambda表达式包含在S的类范围中。由于close类型是S的成员,因此可以访问S的私有成员。