下面总结了 Boost.Signals2 API 相对于原始 Boost.Signals 库所做的更改。 我们还提供了一些关于在将现有 Boost.Signals 代码移植到 Boost.Signals2 时处理每个更改的注意事项。
命名空间 boost::signals
已被 boost::signals2
替换,以避免与原始 Boost.Signals 实现以及 Qt "signals" 宏冲突。 所有 Boost.Signals2 类都在 boost::signals2
命名空间内,这与原始 Boost.Signals 不同,后者除了自己的 boost::signals
命名空间外,还有一些类在 boost
命名空间中。
Boost.Signals2 头文件包含在 boost/signals2/
子目录中,而不是原始 Boost.Signals 使用的 boost/signals
子目录。 此外,除了便利头文件 boost/signals2.hpp
之外,所有头文件都在 boost/signals2/
子目录内,这与原始 Boost.Signals 不同,后者除了自己的 boost/signals/
子目录外,还保留了一些头文件在父 boost/
目录中。
例如,signal
类现在位于 boost::signals2
命名空间中,而不是 boost
命名空间中,并且它的头文件现在位于 boost/signals2/signal.hpp
而不是 boost/signal.hpp
。
在移植过程中,只需要对 #include
指令和命名空间限定符进行简单的更改即可处理这些更改。 此外,Boost.Signals2 的新命名空间和头文件位置允许它与原始 Boost.Signals 库在同一程序中共存,并且可以逐步执行移植。
现在,通过使用 shared_ptr
/weak_ptr
和 signals2::slot::track
() 来实现自动连接管理,如 教程中所述。 但是,旧的(线程不安全)Boost.Signals 自动连接管理方案仍然通过 boost::signals2::trackable
类支持。
如果您不打算使您的程序多线程化,则最简单的移植路径是简单地将您使用的 boost::signals::trackable
作为基类替换为 boost::signals2::trackable
。 Boost.Signals2 使用相同的 boost::visit_each
机制来发现 trackable
对象,就像原始 Boost.Signals 库所使用的那样。
通过 shared_ptr
管理的对象上的后构造函数(和预析构函数)的支持已通过 deconstruct
工厂函数添加。 这是由 shared_ptr
对于新的连接跟踪方案的重要性以及无法在其构造函数中获得对象的 shared_ptr
驱动的。 deconstruct
的使用在 教程中进行了描述。
绝不需要使用 deconstruct
,它只是被提供,希望它可能有用。 如果您正在移植一个类在其构造函数中创建与其自身成员函数的连接的代码,并且您还希望使用新的自动连接管理方案,那么您可能希望使用它。 然后,您可以将连接创建从构造函数移动到 adl_postconstruct
函数,其中可以获得对拥有的 shared_ptr
的引用,以传递给 signals2::slot::track
。 deconstruct
函数将用于创建类的对象并运行其关联的 adl_postconstruct
函数。 您可以通过使类的构造函数私有并将 deconstruct_access
声明为友元来强制使用 deconstruct
。
signals2::slot
类采用一个新的 Signature
模板参数,可以用作函数对象,并且具有一些附加功能来支持新的 Boost.Signals2 自动连接管理方案。
对 slot 类的更改通常不会导致任何移植困难,特别是如果您使用上面提到的 boost::signals2::trackable
兼容性类。 如果您正在将您的代码转换为使用新的自动连接管理方案,您将需要使用一些新的 slot 功能,如 教程中所述。
optional_last_value
类已替换 last_value
作为信号的默认组合器。
仍然提供了 signals2::last_value
组合器,尽管它的行为略有改变,因为它在信号调用时没有连接任何 slot 时会抛出异常,而不是总是要求至少连接一个 slot(除了它的 void 特化,它从不需要连接任何 slot)。
如果您正在移植的信号在其签名中具有 void
返回类型,并且它们使用默认组合器,则不需要进行任何更改。 如果您使用具有非 void 返回类型的默认组合器并且关心从信号调用返回的值,您将必须考虑到 optional_last_value
返回一个 boost::optional
而不是一个普通值。 处理这个问题的一个简单方法是使用 boost::optional::operator*()
来访问包装在返回的 boost::optional
中的值。
或者,您可以通过指定 signals2::signal
的 Combiner
模板参数为 signals2::last_value
来进行移植。
signals2::signal
类有一个额外的 typedef signals2::signal::extended_slot_type
和新的 signals2::signal::connect_extended
() 方法。 这些允许连接采用额外的 signals2::connection
参数的 slot,从而在调用它们时为它们提供对其信号/slot 连接的线程安全访问。 还有一个新的 ExtendedSlotFunction
模板参数,用于指定新的扩展 slot 的底层 slot 函数类型。
除非您还将您的程序从单线程程序转换为多线程程序,否则这些添加不应影响移植。 在这种情况下,如果您有需要访问调用它们的信号的 signals2::connection
的 slot(例如,阻止或断开它们的连接),您可能希望使用 signals2::signal::connect_extended
() 连接 slot。 这还需要向 slot 添加一个额外的连接参数。 有关如何以及为什么要使用扩展 slot 的更多信息,请参见 教程。
signals2::signal
类有一个新的 Mutex
模板参数,用于指定信号及其连接内部使用的互斥锁类型。
Mutex
模板参数可以保留其默认值 boost::signals2::mutex
,并且对移植的影响应该很小。 但是,如果您有一个单线程程序并且担心不必要的互斥锁锁定会产生性能开销,您可能希望为您的信号使用不同的互斥锁,例如 dummy_mutex
。 有关 Mutex
参数的更多信息,请参见 教程。
signal::combiner()
方法,该方法以前返回对信号组合器的引用,已被 signals2::signal::combiner
(现在按值返回组合器)和 signals2::signal::set_combiner
替换。
在移植过程中,应该可以直接使用新的“按值” signals2::signal::combiner
和 signals2::signal::set_combiner
函数替换旧的返回引用的 signal::combiner()
函数。 但是,您需要检查代码中对 combiner
方法的每个调用,以确定您的程序逻辑是否因更改的返回类型而损坏。
连接不再具有 block()
和 unblock()
方法。 现在通过创建 shared_connection_block
对象来实现连接的阻止,这些对象提供 RAII 样式的阻止。
如果您有现有的 Boost.Signals 代码阻止,例如
namespace bs = boost::signals; bs::connection my_connection; //... my_connection.block(); do_something(); my_connection.unblock();
那么移植到 Boost.Signals2 的版本将如下所示
namespace bs2 = boost::signals2; bs2::connection my_connection; //... { bs2::shared_connection_block blocker(my_connection); do_something(); } // blocker goes out of scope here and releases its block on my_connection
1.56 版本修改了信号析构函数的行为,不再显式调用 disconnect_all_slots。任何与信号析构函数并发运行的信号调用现在应该正常完成,而不是跳过所有剩余的槽。一旦所有并发信号调用完成,与已删除信号的所有连接最终仍将被断开。此更改使 Boost.Signals2 的行为更接近原始 Boost.Signals 库的行为。
1.45 版本添加了 slot::track_foreign
()。此方法允许跟踪由 shared_ptr
类(而非 boost::shared_ptr
)拥有的对象,例如 std::shared_ptr
。
1.40 版本为 shared_connection_block
类添加了一些新特性,使其更加灵活
shared_connection_block
现在可以默认构造。
现在可以在不立即阻止其连接的情况下构造 shared_connection_block
。
添加了 shared_connection_block::connection
() 查询,以提供对 shared_connection_block
相关联的连接的访问。
1.40 版本还引入了 Signals2 的可变参数模板实现,当 Boost 检测到编译器支持可变参数模板时(可变参数模板是 C++11 的一项新特性)将使用该实现。此更改对用户来说大多是透明的,但它确实对接口引入了一些可见的调整,如下所述。
以下库特性已被弃用,仅当您的编译器未使用可变参数模板时可用(即 Boost.Config 定义了 BOOST_NO_CXX11_VARIADIC_TEMPLATES)。
“可移植语法”信号和槽类,即 signals2::signal0、signal1 等。
signals2::signal
和 signals2::slot
类中的 arg1_type、arg2_type 等成员 typedef 已被替换为模板成员类 signals2::signal::arg
和 signals2::slot::arg
。