C++:对象将 lambda 存储到结构中,稍后调用该函数

C++: Object Stores Lambda into a Struct and Later Calls that Function

本文关键字:调用 函数 结构 对象 lambda 存储 C++      更新时间:2023-10-16

完成此操作的正确语法是什么?这个想法是,任何类的某个对象都可以在类 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();
};

大致如下:

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);

根据对讨论的评论,您不能使用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));

也许更好的选择是使用函子。为此,您需要创建一个如下所示的类:

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

然后你可以构建这样的东西:

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