完成此操作的正确语法是什么?想法是任何类的某个对象都可以在类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));
也许更好的选择是使用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));