MongoDB源码:StatusWith

相关的类

  • Status

StatusWith<ResultType> 用于返回结果,如果计算结果的过程中出现错误,则返回错误状态 Status。源码中有一个例子,可以形象的看出 StatusWith 的使用方法。

StatusWith<int> fib( int n ) {
    if ( n < 0 )
        return StatusWith<int>( ErrorCodes::BadValue, "parameter to fib has to be >= 0" );
    if ( n <= 1 ) return StatusWith<int>( 1 );
    StatusWith<int> a = fib( n - 1 );
    StatusWith<int> b = fib( n - 2 );
    if ( !a.isOK() ) return a;
    if ( !b.isOK() ) return b;
    return StatusWith<int>( a.getValue() + b.getValue() );
}

StatusWith 包含一些实现的细节,如:

  • 禁用 StatusWith<Status>StatusWith<StatusWith<T>>
  • TagType
  • transform

下文主要针对这些细节,做了一定的解读。

禁用 StatusWith<Status> 和 StatusWith<StatusWith<T>>

代码中使用如下语句在编译期间检测是否存在 StatusWith<Status>StatusWith<StatusWith<T>>

MONGO_STATIC_ASSERT_MSG(!isStatusOrStatusWith<T>,
                        "StatusWith<Status> and StatusWith<StatusWith<T>> are banned.");

其中 MONGO_STATIC_ASSERT_MSGstatic_assert 的封装,static_assert 在编译期间判断第一个参数对应的表达式是否为 true,如果为 false 则报错。

在这里,表达式为 !isStatusOrStatusWith<T>,该表达式是如何在编译期计算的呢?

// Using extern constexpr to prevent the compiler from allocating storage as a poor man's c++17
// inline constexpr variable.
// TODO delete extern in c++17 because inline is the default for constexpr variables.
template <typename T>
extern constexpr bool isStatusWith = false;
template <typename T>
extern constexpr bool isStatusWith<StatusWith<T>> = true;

template <typename T>
extern constexpr bool isStatusOrStatusWith =
    std::is_same<T, mongo::Status>::value || isStatusWith<T>;

extern constexpr 不太明白其作用

通过 is_same 和 存在特化的isStatusWith 即可在编译期间完成类型的判断。

TagType

TagType 的定义如下:

struct TagTypeBase {
protected:
    TagTypeBase() = default;
};
// `TagType` is used as a placeholder type in parameter lists for `enable_if` clauses.  They
// have to be real parameters, not template parameters, due to MSVC limitations.
class TagType : TagTypeBase {
    TagType() = default;
    friend StatusWith;
};

因此 TagType 内部没有具体的功能,因此其功能在其存在上,如:

template <typename Alien>
StatusWith(Alien&& alien,
            typename std::enable_if_t<std::is_convertible<Alien, T>::value, TagType> = makeTag(),
            typename std::enable_if_t<!std::is_same<Alien, T>::value, TagType> = makeTag())
    : StatusWith(static_cast<T>(std::forward<Alien>(alien))) {}

其中,enable_if_tis_convertibleis_same 配合使用,利用SFINAE的特性,生成符合要求的构造函数,如这里的要求为:

  • Alien 必须能够转换成 T
  • Alien 必须不能为 T

transform

StatusWith 实现了 transform 函数,如果StatusWith 为值,那么对该值应用一个函数,如果 StatusWith 为错误状态,则以该错误状态创建新的 StatusWith 并返回。

template <typename F>
StatusWith<std::invoke_result_t<F&&, T&>> transform(F&& f) & {
    if (_t)
        return {std::forward<F>(f)(*_t)};
    else
        return {_status};
}

其中,invoke_result_t 的原型如下:

template<class F, class... ArgTypes>
class invoke_result;

template< class F, class... ArgTypes>
using invoke_result_t = typename invoke_result<F, ArgTypes...>::type;

F 为可调用的类型,invoke_result 返回该调用类型以 ArgTypes 的参数类型调用的时候的返回值的类型。这里使用 F&& 是为了做完美转发的用途。

参考连接

此外,该函数后面存在一个 &,这是函数引用限定,可以为 &&&,引用限定可以让成员函数只能被左值对象调用或者只能被右值对象调用。

总结

StatusWith 适合在某容易出现错误的计算序列中存储中间的计算结果,可能有利于设计好的错误处理。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,785评论 18 399
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 135,058评论 19 139
  • 小编费力收集:给你想要的面试集合 1.C++或Java中的异常处理机制的简单原理和应用。 当JAVA程序违反了JA...
    八爷君阅读 4,681评论 1 114
  • 简介 C++98/03的设计目标:一、比C语言更适合系统编程(且与C语言兼容)。二、支持数据抽象。三、支持面向对象...
    认真学计算机阅读 5,362评论 0 53
  • 关于Mongodb的全面总结 MongoDB的内部构造《MongoDB The Definitive Guide》...
    中v中阅读 32,056评论 2 89