...世界上最受推崇和专业设计的 C++ 库项目之一。 Herb SutterAndrei Alexandrescu, C++ 编码标准

PrevUpHomeNext

仿真

=delete 仿真
移动语义
Bool 显式转换
作用域枚举

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 使用了一些宏,这些宏将使用 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_ENDBOOST_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_MOVABLEBOOST_THREAD_MOVABLE_ONLY 的类的移动构造函数和赋值中实现可移植的语法。

BOOST_THREAD_RV_REF_BEGBOOST_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' 用作作用域枚举。

但是,存在一些限制

  • 该类型不是 C++ 枚举,因此 'is_enum<future_errc>' 将为 false_type。
  • 仿真的作用域枚举不能在 switch 中或模板参数中使用。对于这些情况,用户需要使用一些宏。

而不是

    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

PrevUpHomeNext