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

sky*_*ack 15 c++ lambda language-lawyer c++14

请考虑以下示例:

#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);
}
Run Code Online (Sandbox Code Playgroud)

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

到现在为止还挺好.如果我以前知道它,我会经常使用这个技巧来避免编写冗余代码.

我现在想知道的是标准中的位置(工作草案很好)这是定义的,因为我无法找到关于它的部分,子弹或其他任何规则.
是否有拉姆达任何限制或它的工作原理完全相同,如果它被定义为一个静态成员函数?

son*_*yao 15

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

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

这意味着lambda闭包类型将在成员函数内声明,即本地类.并根据§14/ 2成员访问控制[class.access]:

(强调我的)

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

这意味着对于λ表达式本身,它可以访问private的成员S,相同的成员函数func.

§8.4.5.1/ 7关闭类型[expr.prim.lambda.closure]:

(强调我的)

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

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


das*_*ght 6

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

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