我正在尝试找出如何使用c ++ 17最优雅地解决此问题的方法(不使用boost!)。我正在开发一个提供UI控件的库。控件应该能够对事件做出反应,并且用户(使用库)应该能够为这些事件添加其处理程序。我想避免使用Command pattern,因为这对于用户来说太复杂了-他只想定义一个函数并将其分配给某些Event和UI控件。这是一些示例代码:
// My library
class Base; // Base class for all the UI controls
class ListBox : public Base {
// handlers reacting on clicking the item in listbox
std::vector<std::variant<std::function<void()>,
std::function<void(int)> click_handlers_;
// handlers reacting on changing the name of the item in listbox
std::vector<std::variant<std::function<void()>,
std::function<void(std::string, std::string)> edit_handlers_;
public:
void AddHandler(Event ev, const std::function< ? ? ? > handler);
};
// USER's code
int main() {
ListBox lb;
lb.AddHandler(Event::Click, [](int index) { DoSomethingWithItem(i); });
lb.AddHandler(Event::Edit, [](std::string old_name, std::string new_name)
{ DoSomethingWithItemNames(old_name, new_name); });
lb.AddHandler(Event::Edit, []() { DoSomeCleanup(); });
}
Event::Edit
类型的事件发生时,它触发需要两个自变量的enum
。此后,DoSomethingWithItemNames()
完成其工作并处理了事件(至少从用户的角度而言)。
第一个问题:对于每个LisBox事件,我必须定义一个单独的处理程序向量。第二个问题:DoSomeCleanup()
方法的第二个参数的类型应该是什么?
是否有任何方法可以统一这些处理程序,以便用户只能使用一个功能ListBox::AddHandler
,而不能单独使用AddHandler()
和AddClickHandler()
之类的功能?当然,应该对函数类型进行静态检查,并且任何类型的不匹配都应在编译时报告给用户。是否有一种标准方法来处理整个概念?请记住,每个控件都有其事件,我的想法是,可以为每个事件分配一个不带参数的处理函数。谢谢。
您可以为每种可能性分别设置重载,使用两个变体进行两次重载,或者仅使用类型为AddEditHandler()
的参数定义一次,该参数可以使用所有三个可能的std::variant
。据我所知,这些是我们当前的选项,不涉及创建从一个基础派生的包装器类,这将再次使它像std::function
一样工作。