2012-08-13 100 views
19

有这样一类:为什么在lambda中不能使用私有方法?

class A { 
public: 
    bool hasGrandChild() const; 

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

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

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一个问题。

+1

闭合类型没有关系到你的类'A',所以自然就不能访问'A'的非公共成员。它也不可能,因为它的名字是不可知的,所以你甚至不能把它变成一个“朋友”。 – 2012-08-13 12:09:23

+2

只是我还是在gcc上做这个工作? http://ideone.com/333qw – pmr 2012-08-13 12:15:30

+0

@pmr:是的,它似乎可以在较老的GCC中工作,但不适用于较新的GCC。 – 2012-08-13 12:28:24

回答

27

这似乎只是在特殊情况下,海湾合作委员会的错误,当拉姆达试图访问从父类中使用完全合格的名称保护成员。 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:

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

然后C++ 11,11.7/1:

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

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

+1

为什么它*应该*工作的很好的解释。 (为什么大多数其他答案在这里是错误的。)+1 – etherice 2013-08-20 13:06:16

0

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

9

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

的类型λ-表达式(其也是 封闭对象的类型)是一个独特的,未命名的非工会类型 - 称为 闭合类型

因为它是不是一个A一个friend独特的类类型,它并没有获得A的私有成员。

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

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

倒不如说“有使用Lambda没有解决方法”,因为一般的解决方法是存在的,尽管他们需要你放弃便捷的lambda语法。例如,您可以:

  1. 编写明确捕捉this它需要任何其他当地人(由下面的Björn博动的评论启发)沿局部类的类型。
  2. 编写一个private方法来代替lambda表达式,并将其作为回调函数传递(例如,为了方便起见使用std::bind)。如果您想捕获this以外的当地人,则可以在呼叫站点使用更多std::bind来执行此操作。
+2

虽然(http://ideone.com/AvsBE)可以使用本地'struct'。你能解释一下这个区别吗? – 2012-08-13 12:13:17

+0

@BjörnPollex:这是一个* local *'struct',这就是为什么它可以访问其包含类型的私有成员(引用该书:*本地类在封闭范围内,并且具有相同的 可以像封闭函数一样访问函数外部的名字*)。你可以说这是一个功能性的解决方法。 – Jon 2012-08-13 12:15:28

+0

@Jon:这并不能解释为什么编译器不会简单地将闭包类型作为它所属类的一个朋友。如果它可以隐式捕获“this”,从而有效地扮演成员函数的角色,则它应该能够访问其他私有成员。 – 2012-08-13 12:20:12

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

等一下。为什么heck不会只是'any_of(begin,end,std :: mem_fn(&A :: hasChild))'而不是?除了轻微的表现处罚。 – pmr 2012-08-13 13:27:30

+0

@pmr - 这主要是为了说明如何访问lambda表达式中的私有成员函数。 – Henrik 2012-08-13 13:30:28

+0

@pmr:性能损失?我不期待一个;对于一个合理的编译器来说,'f'不会改变是很明显的。 – MSalters 2012-08-14 07:13:10

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(); 
} 
相关问题