std::function 作为 class 的朋友
std::function as a friend of the class
考虑这段代码:
#include <functional>
class A{
public:
std::function<void(A* obj)> todo;
void doWork(){
if(todo)
todo(this);
}
private:
void dummy(){}
friend void todo(); // not working
};
int main(int argc, char *argv[])
{
A tmp;
tmp.todo = [](A *obj){
obj->dummy();
};
tmp.doWork();
return 0;
}
当然,我们无法构建此代码,因为 'A::dummy': cannot access private member declared in class 'A'
。
我认为这是不可能的,但是有没有办法从 lambda 声明访问 class A 的私有成员??
friend void todo(); // not working
是的,它不起作用。这声明友元函数是一些名为“todo”的函数。
这与 class 同名成员不同。好友是函数(或 classes),而不是 class 成员。
您在这里面临的根本问题是两个基本 C++ 方面的组合:
std::function<something>
是一个具体的、独立的 class。
每个lambda都是匿名的class,所有lambda都是离散的,不同的匿名classes.
你可以这样声明:
friend class std::function<void(A* obj)>;
但这不会取得任何成果。这将允许 std::function
模板本身访问此 class 的私有成员。因此,如果 C++ 库的 std::function
模板的内部实现中的某些内容需要访问私有 class 成员,它现在可以做到这一点。但是,当然,std::function
本身没有任何东西知道你的 class。
并且由于每个 lambda 本身都是离散的匿名 class,这对任何 lambda 都没有影响。 std::function
本身就是它自己的具体 class,它会影响这些匿名 lambda 的类型擦除。
简而言之,这在C++中是做不到的。你真正想要的是创建一个特定的匿名 lambda class a friend
这个 class。但是C++中没有这样的语法。您必须想出一些其他替代策略,让您的 lambda 表达式可以访问您的 class 的私有成员。
嗯,你不能直接这样做。即使您将 std::function
class 加好友,它也不会加好友 lambda 本身,它有自己的类型,不同于 std::function
.
我要做的是将可以访问选定私有部分的内容传递给 lambda。这个习语的好处是你不会暴露比你需要的更多:
class A {
struct B {
explicit B(A* s) noexcept : self{s} {}
void dummy();
private:
A* self;
};
void dummy();
public:
std::function<void(B)> todo;
void doWork() {
if (todo) todo(B{this});
}
};
因此您传递了一个 B
,它可以访问所有内容,但只公开 dummy
。 class 在我的示例中是私有的,但您可以将其设置为 public,但这是可选的。
你可以像这样实现待办事项功能:
A tmp;
// auto will take the B type, which cannot be named here since it's private.
// Notice we pass by value, since the wrapper contains the pointer.
// Bonus: operator dot works.
// If B would be public, then you could put A::B instead of auto
tmp.todo = [](auto a) {
a.dummy(); // calls dummy, yay!
// a.doWork(); // cannot call do work, not exposed by the wrapper.
};
考虑这段代码:
#include <functional>
class A{
public:
std::function<void(A* obj)> todo;
void doWork(){
if(todo)
todo(this);
}
private:
void dummy(){}
friend void todo(); // not working
};
int main(int argc, char *argv[])
{
A tmp;
tmp.todo = [](A *obj){
obj->dummy();
};
tmp.doWork();
return 0;
}
当然,我们无法构建此代码,因为 'A::dummy': cannot access private member declared in class 'A'
。
我认为这是不可能的,但是有没有办法从 lambda 声明访问 class A 的私有成员??
friend void todo(); // not working
是的,它不起作用。这声明友元函数是一些名为“todo”的函数。
这与 class 同名成员不同。好友是函数(或 classes),而不是 class 成员。
您在这里面临的根本问题是两个基本 C++ 方面的组合:
std::function<something>
是一个具体的、独立的 class。每个lambda都是匿名的class,所有lambda都是离散的,不同的匿名classes.
你可以这样声明:
friend class std::function<void(A* obj)>;
但这不会取得任何成果。这将允许 std::function
模板本身访问此 class 的私有成员。因此,如果 C++ 库的 std::function
模板的内部实现中的某些内容需要访问私有 class 成员,它现在可以做到这一点。但是,当然,std::function
本身没有任何东西知道你的 class。
并且由于每个 lambda 本身都是离散的匿名 class,这对任何 lambda 都没有影响。 std::function
本身就是它自己的具体 class,它会影响这些匿名 lambda 的类型擦除。
简而言之,这在C++中是做不到的。你真正想要的是创建一个特定的匿名 lambda class a friend
这个 class。但是C++中没有这样的语法。您必须想出一些其他替代策略,让您的 lambda 表达式可以访问您的 class 的私有成员。
嗯,你不能直接这样做。即使您将 std::function
class 加好友,它也不会加好友 lambda 本身,它有自己的类型,不同于 std::function
.
我要做的是将可以访问选定私有部分的内容传递给 lambda。这个习语的好处是你不会暴露比你需要的更多:
class A {
struct B {
explicit B(A* s) noexcept : self{s} {}
void dummy();
private:
A* self;
};
void dummy();
public:
std::function<void(B)> todo;
void doWork() {
if (todo) todo(B{this});
}
};
因此您传递了一个 B
,它可以访问所有内容,但只公开 dummy
。 class 在我的示例中是私有的,但您可以将其设置为 public,但这是可选的。
你可以像这样实现待办事项功能:
A tmp;
// auto will take the B type, which cannot be named here since it's private.
// Notice we pass by value, since the wrapper contains the pointer.
// Bonus: operator dot works.
// If B would be public, then you could put A::B instead of auto
tmp.todo = [](auto a) {
a.dummy(); // calls dummy, yay!
// a.doWork(); // cannot call do work, not exposed by the wrapper.
};