为什么LLVM中的Expected <T>实现了Expected <T> &&的两个构造函数?

时间:2019-10-20 08:32:27

标签: c++ llvm

Expected<T>在llvm / Support / Error.h中实现。这是一个带有TError的带标记的联合。

Expected<T>是类型为T的模板类:

template <class T> class LLVM_NODISCARD Expected

但这两个构造函数确实使我感到困惑:

  /// Move construct an Expected<T> value from an Expected<OtherT>, where OtherT
  /// must be convertible to T.
  template <class OtherT>
  Expected(Expected<OtherT> &&Other,
           typename std::enable_if<std::is_convertible<OtherT, T>::value>::type
               * = nullptr) {
    moveConstruct(std::move(Other));
  }

  /// Move construct an Expected<T> value from an Expected<OtherT>, where OtherT
  /// isn't convertible to T.
  template <class OtherT>
  explicit Expected(
      Expected<OtherT> &&Other,
      typename std::enable_if<!std::is_convertible<OtherT, T>::value>::type * =
          nullptr) {
    moveConstruct(std::move(Other));
  }

为什么Expected<T>为相同的实现重复两个构造?为什么不这样做呢?:

template <class OtherT>
Expected(Expected<OtherT>&& Other) { moveConstruct(std::move(Other));}

2 个答案:

答案 0 :(得分:8)

因为根据建议,构造函数是有条件显式的。这意味着,只有满足某些条件(此处是int x; long int y = x; // implicit cast ok Expected<int> ex; Expected<long int> ey = ex; // also ok void* v_ptr; int* i_ptr = static_cast<int*>(v_ptr); // explicit cast required Expected<void*> ev_ptr; auto ei_ptr = static_cast<Expected<int*>>(ev_ptr); // also required T的可转换性)时,构造函数才显式

C ++在C ++ 20之前没有用于此功能的机制(诸如OtherT)。因此,实现需要使用其他机制,例如定义两个不同的构造函数-一个 explicit 和另一个 converting -并确保选择根据条件选择适当的构造函数。这通常是通过SFINAE在explicit(condition)的帮助下完成的,条件已解决。


从C ++ 20开始,应该有一个std::enable_if说明符的条件版本。只需一个定义,实施起来就会容易得多:

explicit

答案 1 :(得分:5)

要理解这一点,我们应该从std::is_convertible开始。根据{{​​3}}:

  

如果虚函数定义To test() { return std::declval<From>(); }的格式正确,(即std::declval<From>()可以使用隐式转换转换为To,或者From和{ {1}}可能是cv限定的void),并提供等于To的成员常量值。否则,值为true。为了进行此检查,在return语句中使用false不被认为是odr-use。

     

执行访问检查就像是从与两种类型都不相关的上下文中进行。仅考虑return语句中表达式的即时上下文的有效性(包括对返回类型的转换)。

这里的重要部分是它仅检查隐式转换。因此,OP中的两种实现意味着:如果std::declval隐式可转换为OtherT,那么T隐式可转换为expected<OtherT>。如果expected<T>要求显式转换为OtherT,则T要求并显式转换为Expected<OtherT>

以下是隐式和显式强制转换及其Expected<T>对应示例

Expected