std::optional是17标准中增加的管理可选值的类模板,以往经验中如果某个函数的返回值可能失败,如何判断这个失败值和传递这个失败值都需要些额外的手段,optional的出现则很好的解决了这个问题。以下是gcc13版本中std::optional源码的个人解析:
std::optional实现内各类型关系
optional
首先是optional模板声明及内部别名:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 template <typename _Tp> class optional : private _Optional_base<_Tp>, private _Enable_copy_move< is_copy_constructible_v<_Tp>, __and_v<is_copy_constructible<_Tp>, is_copy_assignable<_Tp>>, is_move_constructible_v<_Tp>, __and_v<is_move_constructible<_Tp>, is_move_assignable<_Tp>>, optional<_Tp>> { 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_object_v<_Tp> && !is_array_v<_Tp>); private : using _Base = _Optional_base<_Tp>; 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 >;
_Enable_copy_move
为gcc内部的一个helper模板,四个模板参数对应于是否有复制构造、复制赋值、移动构造、移动赋值,其定义和其中一个特化长这样:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 template <bool _Copy, bool _CopyAssignment, bool _Move, bool _MoveAssignment, typename _Tag = void > struct _Enable_copy_move { }; template <typename _Tag> struct _Enable_copy_move <false , true , true , true , _Tag> { constexpr _Enable_copy_move() noexcept = default ; constexpr _Enable_copy_move(_Enable_copy_move const &) noexcept = delete ; constexpr _Enable_copy_move(_Enable_copy_move&&) noexcept = default ; _Enable_copy_move& operator =(_Enable_copy_move const &) noexcept = default ; _Enable_copy_move& operator =(_Enable_copy_move&&) noexcept = default ; };
由于子类optional<T>
内没有没有数据成员固没有声明任何五个特殊成员函数,所以在这里的含义即是如果optional<T>
的T
不拥有复制构造则optional<T>
因该helper父类没有复制构造亦不拥有复制构造,其他三个特殊成员函数同理。
_Optional_base
optional<T>
子类没有数据成员,成员方法皆为父类方法的封装,所以实现还要看这个_Optional_base
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 template <typename _Tp, bool = is_trivially_copy_constructible_v<_Tp>, bool = is_trivially_move_constructible_v<_Tp>> struct _Optional_base : _Optional_base_impl<_Tp, _Optional_base<_Tp>> { constexpr _Optional_base() = default ; template <typename ... _Args, enable_if_t <is_constructible_v<_Tp, _Args...>, bool > = false > constexpr explicit _Optional_base(in_place_t , _Args&&... __args) : _M_payload(in_place, std::forward<_Args>(__args)...) { } template <typename _Up, typename ... _Args, enable_if_t <is_constructible_v<_Tp, initializer_list<_Up>&, _Args...>, bool > = false > constexpr explicit _Optional_base(in_place_t , initializer_list<_Up> __il, _Args&&... __args) : _M_payload(in_place, __il, std::forward<_Args>(__args)...) { } constexpr _Optional_base(const _Optional_base& __other) : _M_payload(__other._M_payload._M_engaged, __other._M_payload) { } constexpr _Optional_base(_Optional_base&& __other) noexcept (is_nothrow_move_constructible_v<_Tp>) : _M_payload(__other._M_payload._M_engaged, std::move (__other._M_payload)) { } _Optional_base& operator =(const _Optional_base&) = default ; _Optional_base& operator =(_Optional_base&&) = default ; _Optional_payload<_Tp> _M_payload; };
_Optional_base
内包含实际存储对象的_Optional_payload<_Tp> _M_payload
,这里为了让这个类型拥有和_Tp
同样的“可平凡复制构造性”、“可平凡移动构造性”,特化了其他三个版本(_Optional_base<_Tp, false, true>
,_Optional_base<_Tp, true, false>
,_Optional_base<_Tp, true, true>
)声明该类的复制构造、移动构造,比如_Optional_base<_Tp, false, true>
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 template <typename _Tp> struct _Optional_base <_Tp, false , true > : _Optional_base_impl<_Tp, _Optional_base<_Tp>> { constexpr _Optional_base() = default ; template <typename ... _Args, enable_if_t <is_constructible_v<_Tp, _Args...>, bool > = false > constexpr explicit _Optional_base(in_place_t , _Args&&... __args) : _M_payload(in_place, std::forward<_Args>(__args)...) { } template <typename _Up, typename ... _Args, enable_if_t <is_constructible_v<_Tp, initializer_list<_Up>&, _Args...>, bool > = false > constexpr explicit _Optional_base(in_place_t , initializer_list<_Up> __il, _Args... __args) : _M_payload(in_place, __il, std::forward<_Args>(__args)...) { } constexpr _Optional_base(const _Optional_base& __other) : _M_payload(__other._M_payload._M_engaged, __other._M_payload) { } constexpr _Optional_base(_Optional_base&& __other) = default ; _Optional_base& operator =(const _Optional_base&) = default ; _Optional_base& operator =(_Optional_base&&) = default ; _Optional_payload<_Tp> _M_payload; };
可以看到和开始的模板类相比仅是复制构造被声明为了=default
,开始的模板类其实也就是_Optional_base<_Tp, false, false>
。这里为了不写很多相同的代码,把涉及_M_payload
的很多封装操作封装进了_Optional_base_impl
,而_M_payload
也通过模板参数_Optional_base_impl<_Tp, _Optional_base<_Tp>>
从子类传递给了父类。
_Optional_base_impl
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 template <typename _Tp, typename _Dp> class _Optional_base_impl { protected : using _Stored_type = remove_const_t <_Tp>; template <typename ... _Args> constexpr void _M_construct(_Args&&... __args) noexcept (is_nothrow_constructible_v<_Stored_type, _Args...>) { static_cast <_Dp*>(this )->_M_payload._M_construct( std::forward<_Args>(__args)...); } constexpr void _M_destruct() noexcept { static_cast <_Dp*>(this )->_M_payload._M_destroy(); } constexpr void _M_reset() noexcept { static_cast <_Dp*>(this )->_M_payload._M_reset(); } constexpr bool _M_is_engaged() const noexcept { return static_cast <const _Dp*>(this )->_M_payload._M_engaged; } constexpr _Tp& _M_get() noexcept { __glibcxx_assert(this ->_M_is_engaged()); return static_cast <_Dp*>(this )->_M_payload._M_get(); } constexpr const _Tp& _M_get() const noexcept { __glibcxx_assert(this ->_M_is_engaged()); return static_cast <const _Dp*>(this )->_M_payload._M_get(); } };
从代码开始的注释中也印证我的推断,_Optional_base_impl
的存在只是为了减少各特化版本中的重复代码。作为父类的_Optional_base_impl
通过static_cast<_Dp*>(this)->_M_payload
来调用子类内的_M_payload
。
_Optional_payload
实际存储值的_Optional_payload
声明:
1 2 3 4 5 6 7 8 9 10 11 template <typename _Tp, bool = is_trivially_destructible_v<_Tp>, bool = is_trivially_copy_assignable_v<_Tp> && is_trivially_copy_constructible_v<_Tp>, bool = is_trivially_move_assignable_v<_Tp> && is_trivially_move_constructible_v<_Tp>> struct _Optional_payload;
又是可平凡析构、可平凡复制、可平凡移动的模板参数,这个实际值管理的子类同样视实际值的平凡性对应不同的_Optional_payload
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 template <typename _Tp> struct _Optional_payload <_Tp, true , true , true > : _Optional_payload_base<_Tp> { using _Optional_payload_base<_Tp>::_Optional_payload_base; _Optional_payload() = default ; }; template <typename _Tp> struct _Optional_payload <_Tp, true , false , true > : _Optional_payload_base<_Tp> { using _Optional_payload_base<_Tp>::_Optional_payload_base; _Optional_payload() = default ; ~_Optional_payload() = default ; _Optional_payload(const _Optional_payload&) = default ; _Optional_payload(_Optional_payload&&) = default ; _Optional_payload& operator =(_Optional_payload&&) = default ; constexpr _Optional_payload& operator =(const _Optional_payload& __other) { this ->_M_copy_assign(__other); return *this ; } }; template <typename _Tp> struct _Optional_payload <_Tp, true , true , false > : _Optional_payload_base<_Tp> { using _Optional_payload_base<_Tp>::_Optional_payload_base; _Optional_payload() = default ; ~_Optional_payload() = default ; _Optional_payload(const _Optional_payload&) = default ; _Optional_payload(_Optional_payload&&) = default ; _Optional_payload& operator =(const _Optional_payload&) = default ; constexpr _Optional_payload& operator =(_Optional_payload&& __other) noexcept (__and_v<is_nothrow_move_constructible<_Tp>, is_nothrow_move_assignable<_Tp>>) { this ->_M_move_assign(std::move (__other)); return *this ; } };
可以看出区别在于非平凡复制、非平凡移动时有特殊的复制赋值、移动赋值,先不管这里为什么这么写,看看这个基类_Optional_payload_base
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 template <typename _Tp> struct _Optional_payload_base { using _Stored_type = remove_const_t <_Tp>; _Optional_payload_base() = default ; ~_Optional_payload_base() = default ; struct _Empty_byte { }; template <typename _Up, bool = is_trivially_destructible_v<_Up>> union _Storage { _Empty_byte _M_empty; _Up _M_value; }; _Storage<_Stored_type> _M_payload; bool _M_engaged = false ; };
_Storage<_Stored_type> _M_payload
即为实际存储的值,template _Storage
为了保证可平凡析构的一致性同样写了个没有声明析构的可平凡析构版本的模板,和特化了一个带有空析构函数的版本:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 template <typename _Up, bool = is_trivially_destructible_v<_Up>> union _Storage { constexpr _Storage() noexcept : _M_empty() { } template <typename ... _Args> constexpr _Storage(in_place_t , _Args&&... __args) : _M_value(std::forward<_Args>(__args)...) { } template <typename _Vp, typename ... _Args> constexpr _Storage(std::initializer_list<_Vp> __il, _Args&&... __args) : _M_value(__il, std::forward<_Args>(__args)...) { } #if __cplusplus >= 202002L template <typename _Fn, typename _Arg> constexpr _Storage(_Optional_func<_Fn> __f, _Arg&& __arg) : _M_value(std::__invoke(std::forward<_Fn>(__f._M_f), std::forward<_Arg>(__arg))) { } #endif _Empty_byte _M_empty; _Up _M_value; }; template <typename _Up> union _Storage <_Up, false > { _GLIBCXX20_CONSTEXPR ~_Storage() { } };
从上面这部分代码可以看出optional
实际存储在该union
中。_Optional_payload_base
中的_M_engaged
表示实际是否存储值,由于字节对齐,一个optional<T>
的大小可能将占用更大的内存。
以optional<int32_t>
对象为例,其结构为这样:
std::optional成员函数实现
构造函数
以template < class U = T >constexpr optional( U&& value );
为例,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 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 )) { }
_Base
即是_Optional_base<_Tp>
,通过in_place
标签构造:
1 2 3 4 5 6 7 template <typename ... _Args, enable_if_t <is_constructible_v<_Tp, _Args...>, bool > = false > constexpr explicit _Optional_base(in_place_t , _Args&&... __args) : _M_payload(in_place, std::forward<_Args>(__args)...) { }
构造_M_payload
,_Optional_payload
使用基类_Optional_payload_base
的构造:
1 2 3 4 5 6 template <typename ... _Args>constexpr _Optional_payload_base(in_place_t __tag, _Args&&... __args) : _M_payload(__tag, std::forward<_Args>(__args)...), _M_engaged(true ) { }
至最终_Storage
构造:
1 2 3 4 5 template <typename ... _Args> constexpr _Storage(in_place_t , _Args&&... __args) : _M_value(std::forward<_Args>(__args)...) { }
以上即为optional
其中一个构造的全过程。
reset
从上述构造函数的过程可以看出实际操作都是在payload
类型里,这里也就不多描述外层接口,_Optional_payload_base
的_M_reset
过程:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 constexpr void _M_destroy() noexcept { _M_engaged = false ; _M_payload._M_value.~_Stored_type(); } constexpr void _M_reset() noexcept { if (this ->_M_engaged) _M_destroy(); }
emplace
1 2 3 4 5 6 7 8 9 10 11 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(); }
省略中间代码,_Optional_payload_base
中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 template <typename ... _Args> constexpr void _M_construct(_Args&&... __args) noexcept (is_nothrow_constructible_v<_Stored_type, _Args...>){ std::_Construct(std::__addressof(this ->_M_payload._M_value), std::forward<_Args>(__args)...); this ->_M_engaged = true ; } constexpr _Tp&_M_get() noexcept { return this ->_M_payload._M_value; }
_M_construct
在_M_payload._M_value
上原地构造对象后置_M_engaged
为true
。
swap
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 _GLIBCXX20_CONSTEXPR void swap (optional& __other) noexcept (is_nothrow_move_constructible_v<_Tp> && is_nothrow_swappable_v<_Tp>) { using std::swap; if (this ->_M_is_engaged() && __other._M_is_engaged()) swap (this ->_M_get(), __other._M_get()); else if (this ->_M_is_engaged()) { __other._M_construct(std::move (this ->_M_get())); this ->_M_destruct(); } else if (__other._M_is_engaged()) { this ->_M_construct(std::move (__other._M_get())); __other._M_destruct(); } }
逻辑也比较简单不赘述,这里再贴下_M_destruct
实现:
1 2 3 4 constexpr void _M_destruct() noexcept { static_cast <_Dp*>(this )->_M_payload._M_destroy(); }
1 2 3 4 5 6 7 constexpr void _M_destroy() noexcept { _M_engaged = false ; _M_payload._M_value.~_Stored_type(); }