关于lambdas,函数指针的转换和私有数据成员的可见性

时间:2018-02-05 16:24:21

标签: c++ lambda c++14 language-lawyer

考虑以下示例:

#include <cassert>

struct S {
    auto func() { return +[](S &s) { s.x++; }; }
    int get() { return x; }

private:
    int x{0};
};

int main() {
    S s;
    s.func()(s);
    assert(s.get() == 1);
}

它用G ++和clang编译,所以我很想期望标准允许这样做。 但是,lambda没有捕获列表,因为+强制转换为函数指针,所以它不能拥有它。因此,我预计不允许访问S的私人数据成员 相反,如果它被定义为静态成员函数,它的行为或多或少。

到目前为止,这么好。如果我之前知道它,我会经常使用这个技巧来避免编写冗余代码。

我现在想知道的是标准中的位置(工作草案很好)这是定义的,因为我无法找到章节,子弹或其他任何规则它。
是否对lambda有任何限制,或者它完全,就像它被定义为静态成员函数一样?

2 个答案:

答案 0 :(得分:15)

对于成员函数内的lambda表达式,根据§8.4.5.1/2 Closure types [expr.prim.lambda.closure]

  

闭包类型在包含相应lambda表达式的最小块作用域,类作用域或命名空间作用域中声明。

这意味着lambda闭包类型将在成员函数内声明,即本地类。根据{{​​3}}:

(强调我的)

  

类的成员还可以访问该类有权访问的所有名称。 成员的本地类   函数可以访问成员函数本身可以访问的相同名称

这意味着对于lambda表达式本身,它可以访问private的{​​{1}}成员,与成员函数S相同。

§14/2 Member access control [class.access]

(强调我的)

  

非泛型lambda表达式的闭包类型,没有lambda-capture,其约束(如果有的话)满足了指向函数的转换函数,C ++语言链接具有与闭包类型相同的参数和返回类型#39; s函数调用操作符。 ... 此转换函数返回的值是函数F的地址,在调用时,它与调用闭包类型的函数调用运算符具有相同的效果。

这意味着当调用转换的函数指针时,适用相同的规则。

答案 1 :(得分:6)

  

但是,lambda没有捕获列表,因为+强制转换为函数指针,所以它不能拥有它。

+不会强制转换为函数指针,但会将转换运算符添加到指向函数的指针,以供您用作选项。 Lambda仍然是lambda,具有授予它的所有访问权限,即它可以访问成员函数本身可以访问的相同名称。