首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >为什么LLVM中的Expected<T>为Expected<T>&&实现了两个构造函数?

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

Stack Overflow用户
提问于 2019-10-20 08:32:27
回答 2查看 587关注 0票数 7

Expected<T>在llvm/Support/Error.h中实现。它是一个有标记的工会,持有TError

Expected<T>是一个具有T类型的模板类。

代码语言:javascript
运行
复制
template <class T> class LLVM_NODISCARD Expected

但这两个建设者真的把我搞糊涂了:

代码语言:javascript
运行
复制
  /// 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>要为相同的实现重复两个构造?为什么它不这样做呢?

代码语言:javascript
运行
复制
template <class OtherT>
Expected(Expected<OtherT>&& Other) { moveConstruct(std::move(Other));}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-10-20 08:50:30

因为根据建议,该构造函数是有条件地显式。这意味着只有满足某些条件(这里,TOtherT的可转换性),构造函数才是显式的。

C++在explicit(condition)之前没有这种功能的机制。因此,实现需要使用其他机制,例如两个不同构造函数的定义--一个是显式的,另一个是转换的--并确保根据条件选择合适的构造函数。这通常是通过SFINAE在std::enable_if的帮助下完成的,在那里条件是被解决的。

从C++20开始,应该有一个explicit说明符的条件版本。那么,用一个定义来实现就容易多了:

代码语言:javascript
运行
复制
template <class OtherT>
explicit(!std::is_convertible_v<OtherT, T>)
Expected(Expected<OtherT> &&Other)
{
   moveConstruct(std::move(Other));
}
票数 7
EN

Stack Overflow用户

发布于 2019-10-20 08:50:22

要理解这一点,我们应该从std::is_convertible开始。根据优先选择

如果虚函数定义To test() { return std::declval<From>(); }格式良好(也就是说,可以使用隐式转换将std::declval<From>()转换为To,或者FromTo都可能是cv限定的From),则提供等于true的成员常量值。否则值为false。出于本检查的目的,返回语句中使用std::declval不被视为odr-use。 访问检查就像从与任何类型无关的上下文中执行一样。只考虑返回语句中表达式的直接上下文的有效性(包括对返回类型的转换)。

这里重要的部分是它只检查隐式转换。因此,在您的操作中,这两个实现的意思是,如果OtherT隐式地可转换为T,那么expected<OtherT>就隐式地可转换为expected<T>。如果OtherT需要对T的显式强制转换,那么Expected<OtherT>需要并显式地强制转换到Expected<T>

下面是隐式和显式强制转换及其Expected对应的示例

代码语言:javascript
运行
复制
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
票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/58471254

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档