标准库出发,了解optional的用法

本文详细介绍了C++标准库中optional类的用法,包括其两种状态、构造方式(如单参数构造、使用其他optional对象构造等)、操作符重载(如=、*、->、bool、has_value、value、value_or等)以及相关辅助类和make_optional函数的使用。
摘要由CSDN通过智能技术生成

前言

本编文章,从标准库出发,解析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分支处理

  1. 如果optional不为空,返回存储的值的引用
  2. 如果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分支处理

  1. 如果optional不为空,返回存储的值的引用
  2. 如果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对象相匹配的可以为如下:

  1. nullopt对象
  2. 可比较的optional对象
  3. 可比较的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) {}
...
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值