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

时间:2012-08-13 12:06:20

标签: c++ c++11 lambda

有这样的课程:

class A {
public:
    bool hasGrandChild() const;

private:
    bool hasChild() const;
    vector<A> children_;
};

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

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

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

修改 似乎我发布它的代码原来是有效的。我认为它是等价的,但是does not work on 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;
}

似乎完全限定名称this does not work存在问题,但是this works

5 个答案:

答案 0 :(得分:29)

当lambda尝试使用完全限定名称从父类访问受保护的成员时,它似乎只是一个特殊情况下的GCC错误。 This does not work

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();
    });
  }  
};

,但是this works

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

根据C ++ 11,5.1.2 / 3:

  

lambda表达式的类型(也是表达式的类型)   closure object)是一个唯一的,未命名的非联合类类型 - 称为   闭包类型 - 其属性如下所述。这个类类型   不是聚合(8.5.1)。 闭包类型在声明中声明   包含的最小块范围,类范围或命名空间范围   相应的lambda表达式

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

  

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

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

答案 1 :(得分:9)

标准(C ++ 11,§5.1.2/ 3)表明

  

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

由于它是friend A的唯一类类型,因此无法访问A的私有成员。

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

关于可能的解决方法

更新

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

  1. 编写一个本地类类型,明确捕获this以及它需要的任何其他本地人(受BjörnPollex在下面的评论的启发)。
  2. 编写private方法而不是lambda,并将其作为回调传递(例如,为方便起见使用std::bind)。如果您想要在this之外捕获本地人,则可以在呼叫网站上使用更多std::bind来执行此操作。

答案 2 :(得分:3)

解决方法:

typedef  bool (A::*MemFn)(void) const;

bool A::hasGrandChild() const {
    MemFn f = &A::hasChild;
    return any_of(childs_.begin(), childs_.end(), [=](A const &a) {
            return (a.*f)();
    });
}

答案 3 :(得分:3)

您可以明确捕获this并使其成为可以访问私人成员的“成员lambda”。

例如,请考虑以下示例:

#include <iostream>
class A {
private:
    void f() { std::cout << "Private"; }
public:
    void g() { 
        [this] { 
            f(); 
            // doesn't need qualification 
        }(); 
    }
};
class B {
private:
    void f() { std::cout << "Private"; }
public:
    void g() { [] { f(); }(); } // compiler error
};
int main() {
    A a;
    a.g();
}

答案 4 :(得分:0)

这是不可能的,因为lambda不是该类的一部分。它与创建一个类外函数相同,并调用它而不是创建一个lambda。当然,它无法访问私人会员。