C++11 允许使用 '= delete' 删除一些隐式生成的函数,例如构造函数和赋值运算符,如下所示:
public: thread(thread const&) = delete;
在不支持此功能的编译器上,Boost.Thread 依赖于部分模拟,它将函数声明为私有且没有定义。
private: thread(thread &);
此模拟是部分的,因为私有函数可用于某些编译器的重载解析,并使其优先于需要转换的其他重载。请参见下文对移动语义模拟的影响。
为了实现可移动类、移动参数和返回类型,Boost.Thread 在编译器支持时使用右值引用。在不支持右值引用的编译器上,Boost.Thread 使用 Boost.Move 提供的模拟或 Boost.Thread 的先前版本提供的模拟,具体取决于BOOST_THREAD_USES_MOVE
是否已定义。当BOOST_THREAD_VERSION
为 2 时,此宏默认情况下未设置。从BOOST_THREAD_VERSION
3 开始,定义了BOOST_THREAD_USES_MOVE
。
在 1.50 版之前,Boost.Thread 使用其自身的移动语义模拟,该模拟比 Boost.Move 提供的模拟限制更多。此外,Boost.Thread 使用 Boost.Move 对整个 Boost 社区来说都是很有意义的,以便可以将 boost::thread 存储在支持可移动的容器中。
为了至少在某些版本中保持向后兼容性,Boost.Thread 允许用户通过定义 BOOST_THREAD_DONT_USE_MOVE 来使用已弃用的移动语义模拟。
对于不支持右值引用的编译器,移动语义的许多方面都可以模拟,并且 Boost.Thread 遗留版本为此目的提供了工具。
以下是遗留移动语义辅助类和函数的接口。
namespace boost { namespace detail { template<typename T> struct thread_move_t { explicit thread_move_t(T& t_); T& operator*() const; T* operator->() const; private: void operator=(thread_move_t&); }; } template<typename T> boost::detail::thread_move_t<T> move(boost::detail::thread_move_t<T> t); }
我们可以编写一个 MovableOny 类,如下所示。您只需遵循以下简单步骤
detail::thread_move_t<classname>
的转换detail::thread_move_t<classname>
的构造函数detail::thread_move_t<classname>
的赋值运算符例如,thread 类定义了以下内容:
class thread { // ... private: thread(thread&); thread& operator=(thread&); public: detail::thread_move_t<thread> move() { detail::thread_move_t<thread> x(*this); return x; } operator detail::thread_move_t<thread>() { return move(); } thread(detail::thread_move_t<thread> x) { thread_info=x->thread_info; x->thread_info.reset(); } thread& operator=(detail::thread_move_t<thread> x) { thread new_thread(x); swap(new_thread); return *this; } // ... };
BOOST_THREAD_NO_COPYABLE(CLASS)
BOOST_THREAD_MOVABLE(CLASS)
BOOST_THREAD_MOVABLE_ONLY(CLASS)
BOOST_THREAD_COPYABLE_AND_MOVABLE(CLASS)
BOOST_THREAD_RV_REF(TYPE)
,BOOST_THREAD_RV_REF_BEG
和 BOOST_THREAD_RV_REF_END
BOOST_THREAD_RV(V)
BOOST_THREAD_MAKE_RV_REF(RVALUE)
BOOST_THREAD_DCL_MOVABLE
,BOOST_THREAD_DCL_MOVABLE_BEG(T1)
和 BOOST_THREAD_DCL_MOVABLE_END
为了使库代码可移植,Boost.Thread 使用一些宏,这些宏将使用 Boost.Move 提供的宏或 Boost.Thread 的先前版本提供的已弃用的移动语义。
请参阅 Boost.Move 文档,以了解有关如何声明新的可移动类及其限制的完整说明。
BOOST_THREAD_RV_REF(TYPE)
等效于 BOOST_RV_REF(TYPE)
BOOST_THREAD_RV_REF_BEG
等效于 BOOST_RV_REF_BEG(TYPE)
BOOST_THREAD_RV_REF_END
等效于 BOOST_RV_REF_END(TYPE)
BOOST_THREAD_FWD_REF(TYPE)
等效于 `BOOST_FWD_REF(TYPE)`此外,还需要以下宏才能使代码可移植
BOOST_THREAD_RV(V)
宏用于从 BOOST_THREAD_RV_REF(TYPE) 访问右值。BOOST_THREAD_MAKE_RV_REF(RVALUE)
创建一个右值。BOOST_THREAD_DCL_MOVABLE(CLASS)
用于避免与 Boost.Move 冲突BOOST_THREAD_DCL_MOVABLE_BEG(T1)
和 BOOST_THREAD_DCL_MOVABLE_END
是当参数是模板实例化时的 BOOST_THREAD_DCL_MOVABLE
的变体。提供其他宏,并且必须将其包含在公共部分
BOOST_THREAD_NO_COPYABLE
声明一个不可复制的类,或者删除复制构造函数和复制赋值运算符,或者将其移至私有部分。BOOST_THREAD_MOVABLE(CLASS)
声明所有隐式转换为右值引用。BOOST_THREAD_MOVABLE_ONLY(CLASS)
等效于 BOOST_MOVABLE_BUT_NOT_COPYABLE(CLASS)
BOOST_THREAD_COPYABLE_AND_MOVABLE(CLASS)
等效于 BOOST_COPYABLE_AND_MOVABLE(CLASS)
此宏将类标记为不可复制,禁用复制构造和赋值。
此宏将类标记为可移动,声明所有隐式转换为右值引用。
此宏将类型标记为可移动但不可复制,禁用复制构造和赋值。用户需要编写移动构造函数/赋值运算符才能完全编写可移动但不可复制的类。
此宏将类型标记为可复制和可移动。用户需要编写移动构造函数/赋值运算符和复制赋值运算符才能完全编写可复制和可移动的类。
此宏用于在标记为 BOOST_THREAD_COPYABLE_AND_MOVABLE
或 BOOST_THREAD_MOVABLE_ONLY
的类的移动构造函数和赋值运算符中实现可移植语法。
当参数以>
结尾时,使用BOOST_THREAD_RV_REF_BEG
和BOOST_THREAD_RV_REF_END
可以避免编译器错误。
虽然Boost.Move模拟允许使用点运算符访问右值引用BOOST_THREAD_RV_REF(TYPE)
,但遗留定义使用operator->
。因此,我们需要一个宏BOOST_THREAD_RV
来掩盖这种差异。例如:
thread(BOOST_THREAD_RV_REF(thread) x) { thread_info=BOOST_THREAD_RV(x).thread_info; BOOST_THREAD_RV(x).thread_info.reset(); }
使用这些宏大大减少了Boost.Thread移动相关代码的规模。
虽然Boost.Move是最好的C++03移动模拟,但它也有一些限制会影响库的使用方式。例如,使用以下声明:
class thread { // ... private: thread(thread &); public: thread(rv<thread>&); // ... };
即使thread可以转换为rv<thread>
,这在某些编译器上也可能无法工作,因为编译器更倾向于使用私有的复制构造函数。
thread mkth() { return thread(f); }
在这些编译器上,我们需要使用显式转换。库提供了一个移动成员函数来解决这个问题。
thread mkth() { return thread(f).move(); }
请注意,在这种情况下不能使用::boost::move
,因为thread不能隐式转换为thread&
。
thread mkth() { return ::boost::move(thread(f)); }
为了使Boost.Thread代码可移植,用户需要使用宏BOOST_THREAD_MAKE_RV_REF
,其使用方法如下:
thread mkth() { return BOOST_THREAD_MAKE_RV_REF(thread(f)); }
请注意,此限制也适用于遗留的Boost.Thread移动模拟。
由于Boost.Move也定义了boost::move
函数,我们需要专门化has_move_emulation_enabled_aux
元函数。
template <> struct has_move_emulation_enabled_aux<thread> : BOOST_MOVE_BOOST_NS::integral_constant<bool, true> {};
以便禁用以下Boost.Move重载:
template <class T> inline typename BOOST_MOVE_BOOST_NS::disable_if<has_move_emulation_enabled_aux<T>, T&>::type move(T& x);
宏BOOST_THREAD_DCL_MOVABLE(CLASS)
、BOOST_THREAD_DCL_MOVABLE_BEG(T1)
和BOOST_THREAD_DCL_MOVABLE_END
用于此目的。例如:
BOOST_THREAD_DCL_MOVABLE(thread)
和
BOOST_THREAD_DCL_MOVABLE_BEG(T) promise<T> BOOST_THREAD_DCL_MOVABLE_END
当编译器提供时,锁提供显式布尔转换运算符。
explicit operator bool() const;
库提供了一个隐式转换为未定义类型的转换,该类型可以用作条件表达式。
#if defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS) operator unspecified-bool-type() const; bool operator!() const; #else explicit operator bool() const; #endif
当需要显式转换时,用户应使用lock.owns_lock()。
如果owns_lock()
将返回true
,则返回在布尔上下文中计算结果为true
的值;否则,返回在布尔上下文中计算结果为false
的值。
无。
!
owns_lock()
。
无。
标准库中定义的一些枚举是作用域枚举。
在不支持作用域枚举的编译器上,库使用一个类来包装底层类型。而不是
enum class future_errc { broken_promise, future_already_retrieved, promise_already_satisfied, no_state };
库将这些类型声明为
BOOST_SCOPED_ENUM_DECLARE_BEGIN(future_errc) { broken_promise, future_already_retrieved, promise_already_satisfied, no_state } BOOST_SCOPED_ENUM_DECLARE_END(future_errc)
这些宏允许在几乎所有情况下将'future_errc'用作作用域枚举。
但是,也有一些限制
而不是
switch (ev) { case future_errc::broken_promise: // ...
使用
switch (boost::native_value(ev)) { case future_errc::broken_promise:
而不是
#ifdef BOOST_NO_CXX11_SCOPED_ENUMS template <> struct BOOST_SYMBOL_VISIBLE is_error_code_enum<future_errc> : public true_type { }; #endif
使用
#ifdef BOOST_NO_CXX11_SCOPED_ENUMS template <> struct BOOST_SYMBOL_VISIBLE is_error_code_enum<future_errc::enum_type> : public true_type { }; #endif