【问题标题】:C++: Object Stores Lambda into a Struct and Later Calls that FunctionC++:对象将 Lambda 存储到结构中,然后调用该函数
【发布时间】:2020-06-14 00:33:25
【问题描述】:

完成此操作的正确语法是什么?这个想法是任何类的某些对象都可以在 GuiButton 类中存储 lambda 表达式,然后调用该 lambda 表达式并访问其自己的局部变量。

需要注意的是,我的平台(Arduino)不支持functional 标头。

我编写的代码试图表达这个想法(由于 lambda 表达式无法访问 ExampleScreen 的成员,因此无法编译):

struct GuiButton {
    uint8_t x;  //coordinates for displaying this GUI element
    uint8_t y;
    GuiButton(uint8_t _x, uint8_t _y, void (*_callback)()) :
      x(_x),
      y(_y),
      callback(_callback)
      {};
    virtual void draw(bool _highlight);
  public:
    void (*callback)();   //to be executed BY THE PARENT OBJECT when this element is clicked
};

struct GuiTextButton: public GuiButton {
  char* text;   //text to display in this GUI element
  GuiTextButton(uint8_t _x, uint8_t _y, char* _text, void (*_callback)()) :
    GuiButton(_x, _y, _callback),
    text(_text)
    {};
  void draw(bool _highlight);
};

class ExampleScreen{
  private:
    GuiButton** buttonPtr;
    uint8_t buttonCount;
    uint8_t selectedButton;
    bool proc1Active;
    bool proc2Active;
  public:
    ExampleScreen() : 
      buttonPtr(NULL),
      buttonCount(0),
      selectedButton(0),
      proc1Active(false),
      proc2Active(false)
        {
          //different derived classes of GuiScreen shall have different constructors to define
          //their visual and functional elements
          buttonPtr = new GuiButton* [2];
          buttonCount = 2;
          {
            char text[] = "Button1";
            GuiButton *_thisPtr = new GuiTextButton(5,0,text, []() {
              proc1Active = ~proc1Active;
            });
            buttonPtr[0] = _thisPtr;
          }
          {
            char text[] = "Button2";
            GuiButton *_thisPtr = new GuiTextButton(5,0,text, []() {
              proc2Active = ~proc2Active;
            });
            buttonPtr[2] = _thisPtr;
          }
        };
    void click() {
      void (*callback)() = (buttonPtr[selectedButton]->callback);
      callback();
    };
};

int main() {
  ExampleScreen gui;
  gui.click();
};

【问题讨论】:

  • 您的 lambda 表达式需要捕获 this。但随后它们将无法转换为普通函数指针。所以,无论你在哪里使用 void (*_callback)() 或类似名称,都将其更改为 std::function<void()> _callback
  • 我忘了提到我无法访问 functional 标头。问题已更新,谢谢!
  • 那你根本不能这样做。不幸的是,C++ 不能以这种方式工作。
  • 然后用老式的方式来做。让回调将void* 指针作为参数,其中可以传递上下文。让GuiButton 获取并存储回调和上下文指针;调用回调时将后者传递给前者。在ExampleScreen 中,将this 作为上下文指针传递,让回调将其转换回ExampleScreen*
  • 我不能完全遵循这一点,但它确实看起来合理吗?你能把它更直接地拼出来作为答案吗?

标签: c++ class pointers lambda


【解决方案1】:

类似的东西:

class GuiButton {
  GuiButton(void (*_callback)(void*), void* _context)
      : callback(_callback), context(_context) {}

  // Invoke the callback as callback(context)
  void (*callback)(void*);
  void* context;
};

// In ExampleScreen
new GuiButton([](void* context) {
    auto self = static_cast<ExampleScreen*>(context);
    self->proc1Active = ~self->proc1Active;
}, this);

【讨论】:

    【解决方案2】:

    根据您讨论的 cmets,您不能使用 functional 标头排除简单的解决方案(即让回调为 std::function 并捕获上下文或使用 std::bind 绑定它。

    但是,我认为您仍然可以为所欲为。将callback 的类型设为struct,例如:

    struct CallbackData {
      void (*callback)(ExampleScreen*);
      ExampleScreen* context;
      // obvious constructor here...
    }
    

    然后你可以像这样调用回调:

    callback_data.callback(callback_data.context);
    

    然后你将它传递给GuiButton 构造函数,例如:

    new GuiTextButton(5,0,text,CallbackData([](ExampleScreen* e) { ... }, this));
    

    也许更好的选择是使用functor。为此,您需要像这样创建一个类:

    class GuiButtonCallback {
     public:
      GuiButtonCallback(ExampleScreen* context) : context_(context) {}
      void operator() {
        context->proc1Active = ~context->proc1Active;
      }
     private:
      ExampleScreen* context_;
    };
    

    然后你可以像这样构造:

    new GuiTextButton(5 , 0, text, GuiButtonCallback(this));
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-11-15
      • 1970-01-01
      • 2010-11-10
      • 2013-06-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多