c++ - C++ 从用 lambda 初始化的 C 风格函数指针访问私有成员
问题描述
这是一个简单的窗口类(为简洁起见省略了成员):
class window {
public:
window();
window(const std::string& title, const gt::size2d& size, bool visible = true, bool fullscreen = false);
NO_COPY(window);
window(window&& o);
window& operator=(window&& o);
using close_callback = std::function<void()>;
// members omitted ...
private:
struct impl;
struct impl_deleter {
void operator()(impl* impl);
};
std::unique_ptr<impl, impl_deleter> m_pimpl;
close_callback m_close_callback = []() { DD("Close callback"); };
// ...
};
我的目标是从 GLFW 窗口系统调用 m_close_callback,我可以实现这样的东西:
void close_callback_indirection(GLFWwindow* win)
{
gt::window* winptr = static_cast<gt::window*>(glfwGetWindowUserPointer(win));
if (winptr != nullptr) {
winptr->m_close_callback(); // DOES NOT COMPILE
}
}
gt::window::window(const std::string & title, const gt::size2d & size, bool visible, bool fullscreen)
: m_pimpl{ nullptr }, m_close_callback{ []() {} }, m_size_callback{ [](const gt::size2d&) { } }
{
// omitted GLFW and GL initialization here ...
GLFWwindow* win = glfwCreateWindow(size.x, size.y, title.c_str(), nullptr, nullptr);
m_pimpl.reset(new gt::window::impl);
m_pimpl->glfw_win = win;
glfwSetWindowUserPointer(win, this);
glfwSetWindowCloseCallback(win, close_callback_indirection);
// omitted rest ...
}
正如预期的那样,这不会与消息“'gt::window::m_close_callback':无法访问在类'gt::window'中声明的私有成员”一起编译。
但是,如果我这样实现它:
gt::window::window(const std::string & title, const gt::size2d & size, bool visible, bool fullscreen)
: m_pimpl{ nullptr }, m_close_callback{ []() {} }, m_size_callback{ [](const gt::size2d&) { } }
{
// omitted GLFW and GL initialization here ...
GLFWwindow* win = glfwCreateWindow(size.x, size.y, title.c_str(), nullptr, nullptr);
m_pimpl.reset(new gt::window::impl);
m_pimpl->glfw_win = win;
glfwSetWindowUserPointer(win, this);
// using lambda instead of function pointer
glfwSetWindowCloseCallback(win, [](GLFWwindow* win) {
gt::window* winptr = static_cast<gt::window*>(glfwGetWindowUserPointer(win));
if (winptr != nullptr) {
// Accessing private member here
winptr->m_close_callback(); // WHY THIS WORKS?
}
});
// omitted rest ...
}
现在它编译并且它工作了,如果我按下窗口关闭按钮,我可以看到调试消息。
我的理解是没有捕获列表的 lambda 可以并且在这种情况下将被强制转换为函数指针,所以我猜编译器会在某处生成函数代码并传递一个指向它的指针,但为什么它可以访问窗口对象的私有成员?生成的函数是window(或朋友)的私有成员吗?
我可以依赖这种行为还是这被认为是未定义的?
我正在使用 MSVC++ 编译器
Microsoft (R) C/C++ Optimizing Compiler Version 19.16.27026.1 for x86
解决方案
所有 lambda 都可以访问在其声明点可访问的任何内容。如果您在类的成员函数中创建 lambda,则该 lambda 可以访问该成员函数本身可以访问的任何内容。总是。
当无捕获 lambda 转换为函数指针时,该指针引用的函数与 lambda 本身相同。包括它的可访问性。
推荐阅读
- python - Gmail API 在批量发送期间发送多封邮件
- python - 使用 Python 请求抓取网站时出现属性错误
- java - 当我使用 SimpleForwardingServerCallListener 时,gRPC 上下文返回 null
- reactjs - 从 React 应用程序发出套接字 io 事件并且在 Node js 服务器上没有接收到它
- awk - awk:将行号与结束的正则表达式模式匹配
- python - python3中open()函数的文件路径有问题
- c++ - 在 C++ 中的字符串函数的返回语句中设置精度内联
- python - 使用“left”和“right”参数使用 numpy interp 进行外推
- linux - Index.php:在 apache 中找不到文件
- c++ - C ++中除差表中的牛顿多项式