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); }
在这些编译器上,我们需要改为使用显式转换。该库提供了一个 move 成员函数,允许解决此问题。
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
当编译器提供时,锁提供显式的 bool 转换运算符。
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