C++ 如何在C+中提供像lambda这样的可调用对象保护访问+;?

C++ 如何在C+中提供像lambda这样的可调用对象保护访问+;?,c++,lambda,c++14,C++,Lambda,C++14,我有一个lambda,我需要将它转换成一个可调用对象,以便专门化调用操作符。我的印象一直是,带有void(auto)签名的lambda相当于大致如下所示的可调用结构: struct callable { Foo & capture; template< typename T > void operator()( T arg ) { /* ... */ } } struct可调用{ Foo&capture; 模板 void运算符()(T arg){/

我有一个lambda,我需要将它转换成一个可调用对象,以便专门化调用操作符。我的印象一直是,带有
void(auto)
签名的lambda相当于大致如下所示的可调用结构:

struct callable {
    Foo & capture;

    template< typename T >
    void operator()( T arg ) { /* ... */ }
}
struct可调用{
Foo&capture;
模板
void运算符()(T arg){/*…*/}
}
但是,当lambda在成员函数中声明时,它可以访问私有和受保护的成员

下面是一个简化的示例:

#include <iostream>

using namespace std;

class A {
protected:
    void a() { cout << "YES" << endl; }
};

class B : public A {
public:
    void call1();
    void call2();
};


struct callable {
    B * mB;

    void operator()() {
        // This does not compile: 'void A::a()' is protected within this context
        // mB->a();
    }
};

void B::call1() {
    // but then how does this access a() ?!
    [&]() { a(); }();
}

void B::call2() {
    callable c{ this };
    c();
}


int main()
{
    B b;

    b.call1();
    b.call2();
}
#包括
使用名称空间std;
甲级{
受保护的:

void a(){cout您仍然可以捕获
&B::a

struct callable {
    B* mB;
    void (A::*m)();

    void operator()() const {
        (mB->*m)();
    }
};

void B::call2() {
    callable c{ this, &B::a };
    c();
}

您可以使
B
struct可调用
a
friend
,而无需为其提供定义。在遇到真正的声明之前,这样的声明甚至不会使名称可见:

class B : public A {
  // ...
  friend struct callable;
}

// ERROR: callable isn't visible here:
// callable *foo;
如果简洁真的很重要的话,这可以扩展到通过一个声明攻击大量朋友:

class B : public A {
  // ...
  template<int> friend struct callable;
};

// In implementation:
template<>
struct callable<0> { /* ... */ };
template<>
struct callable<1> { /* ... */ };
B类:公共A类{
// ...
模板友元结构可调用;
};
//在执行中:
模板
结构可调用{/*…*/};
模板
结构可调用{/*…*/};

OP声明“未在标头中声明并使其成为朋友类?”。您不必在标头中给出
callable
的完整定义。我不清楚OP是否认为转发声明是“在标头中声明”.是的,将父类声明为friend并从该类继承可能是一个不错的解决方案,如果friend status是继承的。不幸的是,它不是。您可以使用我添加的模板hack简洁地创建许多friend。(这避免了让一个朋友为您想要使用的
a
的每个成员提供转发功能。)聪明!但是,让我惊讶的是,在实例化callable时,使用
'void a::a()'编译时的错误在此上下文中受到保护。您必须使用
&B::a
。“这样我就可以专门负责呼叫接线员了”——听起来真的是个糟糕的计划。为什么,你愿意重新考虑吗?过载更容易造成麻烦。