MongoDB极简教程 · Mongo · NoSQL

MongoDB源码:StatusWith

2020-11-22  本文已影响0人  江海小流

相关的类

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>>

代码中使用如下语句在编译期间检测是否存在 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的特性,生成符合要求的构造函数,如这里的要求为:

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 适合在某容易出现错误的计算序列中存储中间的计算结果,可能有利于设计好的错误处理。

上一篇下一篇

猜你喜欢

热点阅读