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::signals2::trackable
类来实现旧的(线程不安全)Boost.Signals 自动连接管理方案。
如果您不打算使您的程序多线程化,则最简单的移植路径是简单地将您使用的基类 boost::signals::trackable
替换为 boost::signals2::trackable
。Boost.Signals2 使用与原始 Boost.Signals 库相同的 boost::visit_each
机制来发现 trackable
对象。
通过 deconstruct
工厂函数,增加了对 shared_ptr
管理的对象的后构造函数(和前析构函数)的支持。这是由于 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
组合器,但其行为略有变化,即在信号调用时未连接任何槽时会抛出异常,而不是始终要求至少连接一个槽(其 void 特化除外,它从不需要连接任何槽)。
如果您正在移植签名中具有 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
参数的槽,从而使它们在被调用时可以线程安全地访问其信号/槽连接。还有一个新的 ExtendedSlotFunction
模板参数,用于为新的扩展槽指定底层槽函数类型。
这些添加对移植没有影响,除非您还将程序从单线程程序转换为多线程程序。在这种情况下,如果您的槽需要访问其与调用它们的信号的 signals2::connection
(例如,为了阻止或断开其连接),您可能希望使用 signals2::signal::connect_extended
() 连接这些槽。这还需要向槽添加一个额外的连接参数。有关如何以及为何使用扩展槽的更多信息,请参阅教程。
signals2::signal
类有一个新的 Mutex
模板参数,用于指定信号及其连接内部使用的互斥锁类型。
Mutex
模板参数可以保留其默认值 boost::signals2::mutex
,并且对移植的影响很小。但是,如果您有一个单线程程序,并且担心不必要的互斥锁会导致性能开销,则您可能希望为信号使用不同的互斥锁,例如 dummy_mutex
。有关 Mutex
参数的更多信息,请参阅教程。
以前返回对信号的组合器的引用的 signal::combiner()
方法已被 signals2::signal::combiner
(现在按值返回组合器)和 signals2::signal::set_combiner
替换。
在移植过程中,将旧的返回引用的 signal::combiner()
函数替换为新的“按值” signals2::signal::combiner
和 signals2::signal::set_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 等成员类型定义。它们被模板成员类 signals2::signal::arg
和 signals2::slot::arg
替代。