前言
本编文章,从标准库出发,解析optional类的用法。
如果想要了解optional类的底层是如何实现的,看完本编文章后,可以自己查看optional类继承的两个辅助类。
1 概述
optional对象可以有两种状态。即,表示一个已存在的值或表示不存在。
我们可以令函数返回值的类型为 optional。在调用函数后,我们可以根据返回的optional对象的状态来了解函数的行为。
optional类是开辟一块动态内存去存储值的。
2 解析
1 nullopt_t类型
nullopt_t类的定义和nulloopt对象的定义如下:
struct nullopt_t
{
// Do not user-declare default constructor at all for
// optional_value = {} syntax to work.
// nullopt_t() = delete;
// Used for constructing nullopt.
enum class _Construct { _Token };
// Must be constexpr for nullopt_t to be literal.
explicit constexpr nullopt_t(_Construct) noexcept { }
};
/// Tag to disengage optional objects.
inline constexpr nullopt_t nullopt { nullopt_t::_Construct::_Token };
nullopt是 nullopt_t类型的一个常量对象,作为一个标记,表示 optional对象不存在(没有存储任何值)。
2 前置的静态断言和类型声明(不强求)
先看看能不能看懂, 具体的解释另起代码段,附在了上面
template<typename _Tp>
class optional
{
static_assert(!is_same_v<remove_cv_t<_Tp>, nullopt_t>);
static_assert(!is_same_v<remove_cv_t<_Tp>, in_place_t>);
static_assert(!is_reference_v<_Tp>);
private:
using _Base = _Optional_base<_Tp>;
// SFINAE helpers
template<typename _Up>
using __not_self = __not_<is_same<optional, __remove_cvref_t<_Up>>>;
template<typename _Up>
using __not_tag = __not_<is_same<in_place_t, __remove_cvref_t<_Up>>>;
template<typename... _Cond>
using _Requires = enable_if_t<__and_v<_Cond...>, bool>;
解释
template<typename _Tp>
class optional
{
//_Tp类型不可以是 nullopt_t类型、in_place_t类型、引用类型
static_assert(!is_same_v<remove_cv_t<_Tp>, nullopt_t>);
static_assert(!is_same_v<remove_cv_t<_Tp>, in_place_t>);
static_assert(!is_reference_v<_Tp>);
private:
using _Base = _Optional_base<_Tp>;
// SFINAE helpers
template<typename _Up> //_Up类型参数不是对象类型本身
using __not_self = __not_<is_same<optional, __remove_cvref_t<_Up>>>;
template<typename _Up> //_Up类型参数不是in_place_t类型
using __not_tag = __not_<is_same<in_place_t, __remove_cvref_t<_Up>>>;
template<typename... _Cond> //用来约束只有当_Cond...条件都成立时,bool类型才有效
using _Requires = enable_if_t<__and_v<_Cond...>, bool>;
3 constructor
1 构造无效的optional对象
constexpr optional() noexcept { }
constexpr optional(nullopt_t) noexcept { }
比如:
optional<int> opt = {};
optional<int> opt_(nullopt);
2 使用单参数构造函数构造optional对象
满足下面条件的就是单参数构造函数(可省略)
//满足 _Up不是optional对象,不是in_plade_t对象,_Tp类型可由_Up类型构造,_up类型可转化为_Tp类型
template<typename _Up = _Tp,
_Requires<__not_self<_Up>, __not_tag<_Up>,
is_constructible<_Tp, _Up>,
is_convertible<_Up, _Tp>> = true>
constexpr
optional(_Up&& __t)
noexcept(is_nothrow_constructible_v<_Tp, _Up>)
: _Base(std::in_place, std::forward<_Up>(__t)) { }
template<typename _Up = _Tp,
_Requires<__not_self<_Up>, __not_tag<_Up>,
is_constructible<_Tp, _Up>,
__not_<is_convertible<_Up, _Tp>>> = false>
explicit constexpr
optional(_Up&& __t)
noexcept(is_nothrow_constructible_v<_Tp, _Up>)
: _Base(std::in_place, std::forward<_Up>(__t)) { }
比如
struct A {
int a, b;
A(int a) :a {a}, b{0} {}
};
auto opt3 = std::optional<A>(1)
3 使用optional对象构造
使用存储类型可转换的optional对象构造
template<typename _Up,
_Requires<__not_<is_same<_Tp, _Up>>,
is_constructible<_Tp, _Up>,
is_convertible<_Up, _Tp>,
__not_<__converts_from_optional<_Tp, _Up>>> = true>
constexpr
optional(optional<_Up>&& __t)
noexcept(is_nothrow_constructible_v<_Tp, _Up>)
{
if (__t)
emplace(std::move(*__t));
}
比如:const char*类型可转换为string_view类型
auto opt5 = std::optional<std::string_view>(std::optional("Hello"));
4 显示指示调用构造函数构造对象
in_place_t就一个标志,表示这些参数用于构造对象
template<typename... _Args,
_Requires<is_constructible<_Tp, _Args...>> = false>
explicit constexpr
optional(in_place_t, _Args&&... __args)
noexcept(is_nothrow_constructible_v<_Tp, _Args...>)
: _Base(std::in_place, std::forward<_Args>(__args)...) { }
template<typename _Up, typename... _Args,
_Requires<is_constructible<_Tp,
initializer_list<_Up>&,
_Args...>> = false>
explicit constexpr
optional(in_place_t, initializer_list<_Up> __il, _Args&&... __args)
noexcept(is_nothrow_constructible_v<_Tp, initializer_list<_Up>&,
_Args...>)
: _Base(std::in_place, __il, std::forward<_Args>(__args)...) { }
比如:
struct A {
int a, b;
A(int a, int b) :a{a}, b{b}{}
A(int a) :a {a}, b{0} {}
};
auto opt4 = std::optional<A>(std::in_place, 1, 2);
4 operator= ,emplace
operator=对应于constructor的1、2、3
1 nullopt
operator=(nullopt_t) noexcept
{
this->_M_reset();
return *this;
}
2 使用单参数的构造函数
等号右边的值必须能够调用类型单参数构造函数的
template<typename _Up = _Tp>
enable_if_t<__and_v<__not_self<_Up>,
__not_<__and_<is_scalar<_Tp>,
is_same<_Tp, decay_t<_Up>>>>,
is_constructible<_Tp, _Up>,
is_assignable<_Tp&, _Up>>,
optional&>
operator=(_Up&& __u)
noexcept(__and_v<is_nothrow_constructible<_Tp, _Up>,
is_nothrow_assignable<_Tp&, _Up>>)
3 调用内部类型可转换的optional对象
template<typename _Up>
enable_if_t<__and_v<__not_<is_same<_Tp, _Up>>,
is_constructible<_Tp, const _Up&>,
is_assignable<_Tp&, const _Up&>,
__not_<__converts_from_optional<_Tp, _Up>>,
__not_<__assigns_from_optional<_Tp, _Up>>>,
optional&>
operator=(const optional<_Up>& __u)
noexcept(__and_v<is_nothrow_constructible<_Tp, const _Up&>,
is_nothrow_assignable<_Tp&, const _Up&>>)
4 emplace
对应于constructor中的4
调用与这些参数相匹配的构造函数,构造一个对象,并返回这个对象。
template<typename... _Args>
_GLIBCXX20_CONSTEXPR
enable_if_t<is_constructible_v<_Tp, _Args...>, _Tp&>
emplace(_Args&&... __args)
noexcept(is_nothrow_constructible_v<_Tp, _Args...>)
{
this->_M_reset();
this->_M_construct(std::forward<_Args>(__args)...);
return this->_M_get();
}
template<typename _Up, typename... _Args>
_GLIBCXX20_CONSTEXPR
enable_if_t<is_constructible_v<_Tp, initializer_list<_Up>&, _Args...>,
_Tp&>
emplace(initializer_list<_Up> __il, _Args&&... __args)
noexcept(is_nothrow_constructible_v<_Tp, initializer_list<_Up>&,
_Args...>)
{
this->_M_reset();
this->_M_construct(__il, std::forward<_Args>(__args)...);
return this->_M_get();
}
5 operator*,operator->
1 operator*
定义了适用于不同对象*运算符函数,获取对象的引用
constexpr const _Tp&
operator*() const& noexcept
{ return this->_M_get(); }
constexpr _Tp&
operator*()& noexcept
{ return this->_M_get(); }
constexpr _Tp&&
operator*()&& noexcept
{ return std::move(this->_M_get()); }
constexpr const _Tp&&
operator*() const&& noexcept
{ return std::move(this->_M_get()); }
2 operator->
返回对象的地址,可以用来访问结构体成员
constexpr const _Tp*
operator->() const noexcept
{ return std::__addressof(this->_M_get()); }
constexpr _Tp*
operator->() noexcept
{ return std::__addressof(this->_M_get()); }
6 operator bool, has_value
判断optional对象是否有效
constexpr explicit operator bool() const noexcept
{ return this->_M_is_engaged(); }
constexpr bool has_value() const noexcept
{ return this->_M_is_engaged(); }
7 value, value_or
1 value
定义了适用于不同对象的value函数。用来获取optional对象存储的值。
if分支处理:
- 如果optional不为空,返回存储的值的引用
- 如果optional为空,抛出一个错误
bad_optional_access()
constexpr const _Tp&
value() const&
{
if (this->_M_is_engaged())
return this->_M_get();
__throw_bad_optional_access();
}
constexpr _Tp&
value()&
{
if (this->_M_is_engaged())
return this->_M_get();
__throw_bad_optional_access();
}
constexpr _Tp&&
value()&&
{
if (this->_M_is_engaged())
return std::move(this->_M_get());
__throw_bad_optional_access();
}
constexpr const _Tp&&
value() const&&
{
if (this->_M_is_engaged())
return std::move(this->_M_get());
__throw_bad_optional_access();
}
2 value_or
if分支处理:
- 如果optional不为空,返回存储的值的引用
- 如果optional为空,返回另一个值
template<typename _Up>
constexpr _Tp
value_or(_Up&& __u) const&
{
static_assert(is_copy_constructible_v<_Tp>);
static_assert(is_convertible_v<_Up&&, _Tp>);
if (this->_M_is_engaged())
return this->_M_get();
else
return static_cast<_Tp>(std::forward<_Up>(__u));
}
template<typename _Up>
constexpr _Tp
value_or(_Up&& __u) &&
{
static_assert(is_move_constructible_v<_Tp>);
static_assert(is_convertible_v<_Up&&, _Tp>);
if (this->_M_is_engaged())
return std::move(this->_M_get());
else
return static_cast<_Tp>(std::forward<_Up>(__u));
}
8 reset
销毁optional对象存储的值,也就是释放到管理的内存。
void reset() noexcept { this->_M_reset(); }
9 make_optional
1 使用内置类型
例如:int、float
template<typename _Tp>
constexpr
enable_if_t<is_constructible_v<decay_t<_Tp>, _Tp>,
optional<decay_t<_Tp>>>
make_optional(_Tp&& __t)
noexcept(is_nothrow_constructible_v<optional<decay_t<_Tp>>, _Tp>)
{ return optional<decay_t<_Tp>>{ std::forward<_Tp>(__t) }; }
2 使用构造函数构造
调用与这些参数相匹配的构造函数
// 一系列参数
template<typename _Tp, typename... _Args>
constexpr
enable_if_t<is_constructible_v<_Tp, _Args...>,
optional<_Tp>>
make_optional(_Args&&... __args)
noexcept(is_nothrow_constructible_v<_Tp, _Args...>)
{ return optional<_Tp>{ in_place, std::forward<_Args>(__args)... }; }
//初始化列表 + 一系列参数
template<typename _Tp, typename _Up, typename... _Args>
constexpr
enable_if_t<is_constructible_v<_Tp, initializer_list<_Up>&, _Args...>,
optional<_Tp>>
make_optional(initializer_list<_Up> __il, _Args&&... __args)
noexcept(is_nothrow_constructible_v<_Tp, initializer_list<_Up>&, _Args...>)
{ return optional<_Tp>{ in_place, __il, std::forward<_Args>(__args)... }; }
10 比较运算符
optional类定义了一整套比较运算符以及三路运算符的重载方法
与optional对象相匹配的可以为如下:
- nullopt对象
- 可比较的optional对象
- 可比较的optional存储的数据类型对象
std::optional<int> opt(1);
if (opt == 1) {}
else if (opt < 1.1) {}
else if (opt < std::make_optional(1.1)) {}
else if (opt != nullopt) {}
...