为什么不能在lambda中使用私有方法?

Jur*_*aho 20 c++ lambda c++11

有这样的课程:

class A {
public:
    bool hasGrandChild() const;

private:
    bool hasChild() const;
    vector<A> children_;
};
Run Code Online (Sandbox Code Playgroud)

为什么不能hasChild()在这样的方法中定义的lambda表达式中使用私有方法hasGrandChild()

bool A::hasGrandChild() const {
    return any_of(children_.begin(), children_.end(), [](A const &a) {
        return a.hasChild();
    });
}
Run Code Online (Sandbox Code Playgroud)

编译器发出该方法hasChild()在上下文中是私有的错误.有没有解决方法?

编辑: 似乎我发布它的代码最初有效.我认为它是等价的,但是在GCC上不起作用的代码更像是这样:

#include <vector>
#include <algorithm>

class Foo;

class BaseA {
protected:
    bool hasChild() const { return !children_.empty(); }
    std::vector<Foo> children_;
};

class BaseB {
protected:
    bool hasChild() const { return false; }
};

class Foo : public BaseA, public BaseB {
public:
  bool hasGrandChild() const {
    return std::any_of(children_.begin(), children_.end(), [](Foo const &foo) {
        return foo.BaseA::hasChild();
      });
  }  
};

int main()
{
  Foo foo;
  foo.hasGrandChild();
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

似乎有与完全合格的名字是一个问题,这是行不通的,但这个工程.

Jur*_*aho 29

当lambda尝试使用完全限定名称从父类访问受保护的成员时,它似乎只是一个特殊情况下的GCC错误.这不起作用:

class Base {
protected:
    bool hasChild() const { return !childs_.empty(); }
    std::vector<Foo> childs_;
};

class Foo : public Base {
public:
  bool hasGrandChild() const {
    return std::any_of(childs_.begin(), childs_.end(), [](Foo const &foo) {
      return foo.Base::hasChild();
    });
  }  
};
Run Code Online (Sandbox Code Playgroud)

,但这有效:

class Foo : public Base {
public:
  bool hasGrandChild() const {
    return std::any_of(childs_.begin(), childs_.end(), [](Foo const &foo) {
      return foo.hasChild();
    });
  }  
};
Run Code Online (Sandbox Code Playgroud)

根据C++ 11,5.1.2/3:

lambda表达式的类型(也是闭包对象的类型)是一个唯一的,未命名的非联合类类型 - 称为闭包类型 - 其属性如下所述.此类类型不是聚合(8.5.1).闭包类型在包含相应lambda表达式的最小块作用域,类作用域或命名空间作用域中声明.

然后是C++ 11,11.7/1:

嵌套类是成员,因此具有与任何其他成员相同的访问权限.

因此,提到的函数本地lambda应该具有与该类的任何其他成员相同的访问权限.因此,它应该能够从父类调用受保护的方法.


Jon*_*Jon 9

标准(C++ 11,§5.1.2/ 3)指出

lambda表达式的类型(也是闭包对象的类型)是一个唯一的,未命名的非联合类类型 - 称为闭包类型.

因为它是不是一个独特的类类型friendA,它没有进入A的私有成员.

编译器在这里做的是创建一个类类型,它具有适当的成员来存储任何捕获的变量,一个合适的operator()等等 - 如果你想在C++ 03中模拟lambdas,这正是你自己写的.此类型肯定无法访问private成员,这可能更容易可视化限制存在的原因以及没有解决方法的原因.

有关可能的解决方法的更新:

最好说"没有使用lambda的变通方法",因为一般来说确实存在变通方法,尽管它们要求你放弃方便的lambda语法.例如,您可以:

  1. 编写一个本地类类型,明确地捕获this它所需的任何其他本地化(受BjörnPollex在下面的评论的启发).
  2. 编写一个private方法而不是lambda并将其作为回调传递(例如,std::bind为了方便起见).如果您想要捕获本地人,除了this您可以std::bind在呼叫站点使用更多这样做.

  • 您提到的草案版本是否包含以下内容,或者您​​是否因为某种原因而将其排除在答案之外?*其属性如下所述.此类类型不是聚合(8.5.1).闭包类型在包含相应lambda表达式的最小块作用域,类作用域或命名空间作用域中声明.*我发现它非常相关,尤其是与嵌套类的§11.7相关,如Juraj所述. (3认同)
  • 它适用于本地`struct`(http://ideone.com/AvsBE).你能解释一下这个区别吗? (2认同)