Boost C++ 库

……世界上最受推崇和设计精良的 C++ 库项目之一。 Herb SutterAndrei AlexandrescuC++ 编码规范

PrevUpHomeNext

模拟

=delete 模拟
移动语义
布尔显式转换
作用域枚举

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_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_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);
}

在这些编译器上,我们需要使用显式转换。库提供了一个移动成员函数来解决这个问题。

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

但是,也有一些限制

  • 该类型不是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