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