该篇展示两个基本的概念:函数对象和lambda,其中函数对象是构建Nana的基础。
函数对象(英文上叫function object或functor)就是能像函数那样调用的对象,一般地讲,就是定义了函数调用操作符operator()的类对象。 函数对象是一项非常不错的技术,与普通函数相比更加通用,因为它可以保持调用之后的状态,并且可以对单个对象的初始化和检测,这点通过static的局部变量来实现就很难办到。
class sum
{
public:
sum() : i_(0)
{}
operator int() const volatile
{
return i_;
}
//使类对象可以像函数那样调用
void operator()(int x) volatile
{
i_ += x;
}
private:
int i_;
};
void foo(const std::vector<int>& v)
{
//对所有元素求和
std::cout<<std::for_each(v.begin(), v.end(), sum())<<std::endl;
}
函数对象保持只有自身的状态,因此可以很方便地使用在并行处理中,并且广泛地使用在程序库的实现中以获得良好的灵活性。Nana C++ Library大量地使用了函数对象使该框架得以运行。Nana C++ Library引入了一个通用的函数对象类模板:
template<typename Ftype>
class functor;
模板参数Ftype被指定为需要代理的函数类型。 类模板functor使Nana摆脱了与各种类型的纠缠。例如:
#include <nana/gui/wvl.hpp>
#include <iostream>
void foo()
{
std::system("cls");
std::cout<<"foo"<<std::endl;
}
void foo_with_eventinfo(const nana::gui::eventinfo& ei)
{
std::cout<<"foo_with_eventinfo, mouse pos = ("
<<ei.mouse.x<<", "<<ei.mouse.y<<")"<<std::endl;
}
class click_stat
{
public:
click_stat(): n_(0)
{}
void respond()
{
std::cout<<"click_stat = "<<++n_<<std::endl;
}
void respond_ei(const nana::gui::eventinfo& ei)
{
std::cout<<"click_state width eventinfo = "<<n_
<<", mouse pos = ("<<ei.mouse.x<<", "<<ei.mouse.y<<")"<<std::endl;
}
private:
int n_;
};
int main()
{
using namespace nana::gui;
typedef nana::functor<void()> fun_t;
typedef nana::functor<void(const eventinfo&)> fun_with_param_t;
form fm;
click_stat cs;
fun_t f(foo);
fm.make_event<events::click>(f);
f = fun_t(cs, &click_stat::respond);
fm.make_event<events::click>(f);
fun_with_param_t fp(foo_with_eventinfo);
fm.make_event<events::click>(fp);
fp = fun_with_param_t(cs, &click_stat::respond_ei);
fm.make_event<events::click>(fp);
fm.show();
exec();
}
这里有四种类型的事件处理函数(事件的解释参见文章Hello Nana C++ Library或Programming with Nana C++ Library),并统一地由functor类模板处理。functor类模板提高了灵活度,降低了学习和使用复杂度。
Figure 1.3 方法注册并响应单击事件的各种方法
预定义的函数对象
Nana C++ Library包含了一些不同的预定义的函数对象。用这些函数对象与模板函数一起使用,不但可以增加代码的可读性,而且还能极大提高开发效率。例如,如果一个C++程序想要当点击窗口时关闭该窗口。form.make_event<events::click>(destroy(form));在使用这些函数对象前,请包含<nana/gui/functional.hpp>
class destroy
{
public:
destroy(nana::gui::window wd);
void operator()() const;
};
销毁窗口。
class hide
{
public:
hide(nana::gui::window wd);
void operator()() const;
};
隐藏窗口。
class show
{
public:
show(nana::gui::window wd);
void operator()() const;
};
显示窗口。
Lambda 表达式
Lambda表达式是一个制定函数对象的机制,是最近引入C++的新特性,主要用途为某些函数制定简单的操作。例如:
#include <nana/gui/wvl.hpp>
#include <iostream>
int main()
{
using namespace nana::gui;
form fm;
fm.make_event<events::click>(
[]{ std::cout<<"form is clicked"<<std::endl; }
);
fm.show();
exec();
}
这实参 []{ std::cout<<"form is clicked"<<std::endl; } 在C++(11)语言中是一个"Lambda"(或者 "Lambda函数" 或者 "Lambda 表达式")。Lambda以简单的中括号[]开始,和复合语句块{}来定义一个函数体,实际上,Lambda定义了一个匿名的函数对象,因此可以用函数调用语法来调用这个Lambda,例如
[]{ std::cout<<"form is clicked"<<std::endl; }();
Lambda的作用是创建一个匿名的函数对象,因此也可以为它指定参数列表。例如:
fm.make_event<events::click>(
[](const eventinfo& ei)
{
std::cout<<"mouse pos=("
<<ei.mouse.x<<", "<<ei.mouse.y
<<")"<<std::endl;
}
);
Lambda-declarator()用法于参数列表一样。现在我们暂停对Lambda的介绍,更多的细节请参考C++书籍。