Expected<T>在llvm / Support / Error.h中实现。这是一个标记的并集,包含a T或a Error。
Expected<T>是类型为的模板类T:
template <class T> class LLVM_NODISCARD Expected
Run Code Online (Sandbox Code Playgroud)
但是,这两个构造函数确实使我感到困惑:
/// 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));
}
Run Code Online (Sandbox Code Playgroud)
为什么要Expected<T>针对同一实现重复两个构造?为什么不这样做呢?:
template <class OtherT>
Expected(Expected<OtherT>&& Other) { moveConstruct(std::move(Other));}
Run Code Online (Sandbox Code Playgroud)
因为根据建议,该构造函数在条件上是显式的。这意味着仅当满足某些条件(此处为T和的可转换性OtherT)时,构造函数才是显式的。
explicit(condition)在C ++ 20之前,C ++ 没有针对此功能的机制(诸如)。因此,实现需要使用其他机制,例如定义两个不同的构造函数(一个显式,另一个进行转换),并确保根据条件选择适当的构造函数。通常std::enable_if在条件得以解决的情况下通过SFINAE进行此操作。
从C ++ 20开始,应该有条件的explicit说明符版本。如果使用一个定义,则实现起来会容易得多:
template <class OtherT>
explicit(!std::is_convertible_v<OtherT, T>)
Expected(Expected<OtherT> &&Other)
{
moveConstruct(std::move(Other));
}
Run Code Online (Sandbox Code Playgroud)
要了解这一点,我们应该从开始std::is_convertible。根据cppreference:
如果虚函数定义
To test() { return std::declval<From>(); }是良好的,(即,或者std::declval<From>()可以被转换为To使用隐式转换,或两者From和To是可能的CV-合格空隙),提供了构件恒定值以下的true。否则,值为false。为了进行此检查,std::declval在return语句中使用不被视为odr-use。就像从与这两种类型都不相关的上下文中一样执行访问检查。仅考虑return语句中表达式的即时上下文的有效性(包括对返回类型的转换)。
这里的重要部分是它仅检查隐式转换。因此,OP中的两个实现的意思是,如果OtherT可以隐式转换为T,则expected<OtherT>可以隐式转换为expected<T>。如果OtherT要求显式转换为T,则Expected<OtherT>要求并将显式转换为Expected<T>。
以下是隐式和显式强制转换及其Expected对应示例
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
Run Code Online (Sandbox Code Playgroud)