C++ 中的 GUI 工具包出现问题。将 lambda 传递到 std::function 的向量中

Posted

技术标签:

【中文标题】C++ 中的 GUI 工具包出现问题。将 lambda 传递到 std::function 的向量中【英文标题】:Trouble with a GUI toolkit in C++. Passing lambdas into a vector of std::function 【发布时间】:2019-11-27 17:58:49 【问题描述】:

我遇到的问题有点难以描述,但我会尽力使其易于理解。

我正在创建一个类似于 C# 中的 Windows 窗体系统的 C++ GUI 工具包。整个系统是基于事件的。我的Event 类由std::function 的向量组成,它充当订阅者函数列表和一些实用方法。

template<class T>
class Event

public:

  Event() 
  ~Event() 

  void Raise(T context)
  
    for(std::function<void(T&)> subscriber : Subscribers)
    
      subscriber(context);
    
  

  void Subscribe(std::function<void(T&)> subscriber)
  
    try  Subscribers.push_back(subscriber);  catch (std::exception)  /*...*/ 
  

private:

  std::vector<std::function<void(T&)>>> Subscribers;


我的项目包含一个EventProvider 类,它为所有派生类提供了一堆事件。

class EventProvider

public:

  Event<LoadEventContext> LoadEvent;
  // ...
  // ...


就像在 Windows 窗体中一样,我有一个 Window 类和一个 Control 类。他们都继承了EventProvider。与 C# 中一样,定义所有功能的实际 Window 类必须继承 Window 类。

class Control : public EventProvider  /*...*/ 

class Window : public EventProvider  /*...*/ 

class MyWindow : public Window  /*...*/ 

在我的 MyWindow 类中,我通过 lambda 将方法绑定到 Window 的事件。将MyWindow 类的方法绑定到MyWindow 类的事件可以正常工作。将控件的成员函数绑定到MyWindow 的事件也可以正常工作。在 Windows 窗体中,控件的所有事件方法也包含在 Window 类中。我想在我的项目中做同样的事情。所以MyWindow 类包含我的控件的实例、它自己的事件方法和我的控件的事件方法。但是当我尝试将控制事件函数绑定到控制事件时,我遇到了运行时错误。

// ===  MyWindow.hpp  ===

#ifndef __MY_WINDOW_HPP__
#define __MY_WINDOW_HPP__

#include <Control.hpp>
#include <Window.hpp>

class MyWindow : public Window

public:

  MyWindow();
  ~MyWindow();

private:

  Control* button = nullptr;

  void OnLoadEvent(LoadEventContext& context);
  void button_OnLoadEvent(LoadEventContext& context);



#endif



// ===  MyWindow.cpp ===

#include <MyWindow.hpp>

MyWindow::MyWindow()

  button = new Control();

  LoadEvent.Subscribe([&](LoadEventContext& context)  OnLoadEvent(context); ); // WORKS
  LoadEvent.Subscribe([&](LoadEventContext& context)  button->OnLoadEvent(context); ); // WORKS

  button->OnLoadEvent.Subscribe([&](LoadEventContext& context)  OnLoadEvent(context); ); // Runtime Error


MyWindow::~MyWindow()  /*...*/ 

MyWindow::OnLoadEvent(LoadEventContext& context)  /*...*/ 

MyWindow::button_OnLoadEvent(LoadEventContext& context)  /*...*/ 

//

MyWindow 调用控件的加载事件以将 lambda 函数添​​加到事件的订阅者函数向量中时,会在 stl 的 vector 类中引发读取访问冲突。

这行代码调用事件添加lambda函数:

button->OnLoadEvent.Subscribe([&](LoadEventContext& context)  OnLoadEvent(context); ); // Runtime Error

Event 类中的这个导致了错误:

try  Subscribers.push_back(subscriber);  catch (std::exception)  /*...*/ 

我在函数指针、仿函数、函数类和所有这些东西的编程方面还不是很先进。尽管如此,我希望我已经为您清楚地指出了我的问题,我希望任何人都可以帮助我解决这个问题。

【问题讨论】:

您的代码的哪一行导致了这种情况?使用工具栏上的堆栈框架来计算。 你可能想展示Subscribe()OnLoadEvent()的实现 Subscribe()的实现在Event类中被指出,OnLoadEvent()目前为空。 很抱歉,我不得不为这篇文章将整个系统的复杂性降低到 10%。 不要在问题标题中添加solved。按答案左侧的绿色勾号,将问题标记为已解决。 【参考方案1】:

我明白了。问题是我在创建此控件之前将我的事件方法绑定到我的控件的事件。

【讨论】:

以上是关于C++ 中的 GUI 工具包出现问题。将 lambda 传递到 std::function 的向量中的主要内容,如果未能解决你的问题,请参考以下文章

从 C++ 中的 gui 内创建的对象修改 GUI

将 GUI 附加到命令行工具

Vala GUI 和 C++ 中的逻辑

我应该使用哪个 C++ GUI 库

C++ GUI 中的拖放事件 (WM_DROPFILES)

C++ 或 Python 作为 GUI 编程的起点?