企业🤖AI智能体构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
## Signals ### 头文件: `"boost/signals.hpp"` 通过单个头文件包含了整个库。 ``` "boost/signals/signal.hpp" ``` 包含了 `signal` 的定义。 ``` "boost/signals/slot.hpp" ``` 包含了 `slot` 类的定义。 ``` "boost/signals/connection.hpp" ``` 包含了类 `connection` 和 `scoped_connection` 的定义。 要使用这个库,可以包含头文件 `"boost/signals.hpp"`,这样可以确保整个库可用,或者可以按照你的需要包含单独的头文件。Boost.Signals 库的核心部分定义在名字空间 `boost` 中,高级特性则定义在 `boost::signals` 中。 以下是 `signal` 的部分内容,其后将对其中最主要的成员函数进行了简要的介绍。如果你需要完整的参考,请见 Signals 的在线文档。 ``` namespace boost { template<typename Signature, // Function type R(T1, T2, ..., TN) typename Combiner = last_value<R>, typename Group = int, typename GroupCompare = std::less<Group>, typename SlotFunction = function<Signature> > class signal : public signals::trackable, private noncopyable { public: signal(const Combiner&=Combiner(), const GroupCompare&=GroupCompare()); ~signal(); signals::connection connect(const slot_type&); signals::connection connect( const Group&, const slot_type&); void disconnect(const Group&); std::size_t num_slots() const; result_type operator() (T1, T2, ..., TN); }; } ``` ### 类型 我们先来看看 `signal` 的模板参数。除了第一个参数,其它参数都有相应的缺省值,这有助于理解这些参数的基本意思。第一个模板参数是被调用的函数的签名。在这种 `signal`s 的情况下,`signal` 本身就是被调用的实体。声明这个签名时,使用与普通函数签名相同的语法\[1\]。例如,一个返回 `double` 且接受一个类型 `int` 的参数的函数签名应该象这样: > \[1\] 细心的读者可以已经注意到 `boost::function` 也是这样用的。 ``` signal<double(int)> ``` `Combiner` 参数表示一个函数对象,它负责逐个对该 `signal` 所有已连接的插槽(slot)进行调用。它同时也决定如何将组合这些调用返回的结果。缺省的类型是 `last_value`, 它只是简单地返回最后一个插槽的调用结果。 `Groups` 参数是用于组合所有连接到 `signal` 的插槽的一种类型。通过连接到不同的插槽组,你可以预设调用插槽的顺序,同时也可以断开插槽组。 `GroupCompare` 参数决定了如何排序 `Groups`,缺省值为 `std::less&lt;Group&gt;`, 通常它都是正确的。如果 `Groups` 使用了定制的类型,就有可能需要其它的排序方法。 最后,`SlotFunction` 参数表示插槽函数的类型,缺省值为 `boost::function`. 我想不出有什么理由改变这个缺省值。这个模板参数用于定义插槽的类型,定义的方法是一个公有的 `typedef slot&lt;SlotFunction&gt; slot_type`. ### 成员函数 ``` signal(const Combiner&=Combiner(), const GroupCompare&=GroupCompare()); ``` 在构造一个 `signal` 时,可以传入一个 `Combiner`,它是一个负责在信号到达时调用相应插槽并对返回值进行处理的对象。 ``` ~signal(); ``` 析构函数在析构时断开所有已连接的插槽。 ``` signals::connection connect(const slot_type& s); ``` `connect` 函数把插槽 `s` 连接到 `signal`. 函数指针、函数对象、`bind` 表达式或者 lambda 表达式都可以用作插槽。`connect` 返回一个 `signals::connection`, 它是代表被创建的连接的句柄。通过使用这个句柄,插槽可以从 `signal` 断开,或者你也可以测试该插槽是否还有连接。 ``` signals::connection connect(const Group& g, const slot_type& s); ``` 这个 `connect` 的重载版本与前一个作用相似,但是它还把插槽 `s` 连接到组 `g`. 把一个插槽连接到一个组意味着当一个 `signal` 产生时,属于较前面的组的插槽会先被调用(即按组的顺序来调用,`signal` 模板的 `GroupCompare` 参数定义了组的顺序),而且属于组的所有插槽会在不属于组的插槽之前被调用(可能只有部分插槽是在组中的)。 ``` void disconnect(const Group& g); ``` 断开所有属于组 `g` 的已连接插槽。 ``` std::size_t num_slots() const; ``` 返回当前连接到 `signal` 的插槽数量。要测试插槽是否为空,应该调用函数 `empty`,而不要调用 `num_slots` 并测试其返回是否为0,因为 `empty` 的效率更高。 ``` result_type operator()(T1, T2, ..., TN); ``` `signal`s 使用调用操作符来调用。当信号产生时,必须传递适当的参数给调用操作符,必须符合 `signal` 的签名(即声明 `signal` 类型时的第一个模板参数)。参数的类型必须可以隐式转换为信号所需的类型,只有这样调用才可以成功。 Boost.Signals 中还有其它的类型,我们将在本章剩余部分讨论它们。我们还将讨论 `signal` 类中有用的 `typedef`s。