optional

  • 在实际开发中,我们经常会遇到无效值的情况,例如函数并不是总能返回有效值,很多函数正确执行了,但结果却不是合理的值,如果用数学语言开解释的话,就是返回值位于函数解空间之外。
    求一个数的倒数,在实数域内开平方,在字符串中查找字符串,它们都可能返回“无效值”。有些无效返回的情况可以用抛出异常的方式来通知用户,但有的情况这样的代价很高或者不允许异常。
    表示无效值最常用的做法是增加一个‘哨兵’的角色,它位于解空间之外,如NULL,-1,EOF,string::npos,vector::end()等,但是不通用,而且有时候不存在解空间外的‘哨兵’。
    另外的一个方法是使用pair<T,bool>的方式,用一个额外的bool值标记值是否有效,列如标准容器set.
    optional使用‘容器’语义,包装‘可能产生无效值’的对象,实现‘未初始化’的概念,为无效值的情形提供一个更好的解决方案。optional位于Boost,即:
    #include <boost/optional.hpp>
    using namespace boost;

    • 类摘要:

    optional库首先定义了常量boost::none,明确了‘无效值’的含义:

    namespace detail { struct none_helper{}; }
    typedef int detail::none_helper::*none_t ;		//定义类型none_t
    none_t const one = (static_cat<none_t>(0));		//定义常量one
    

    boost::none的none_t类型实际上是一个成员变量指针,‘指向’并不存在的detail::none_helper的int成员。
    optional库的核心类是optional,它很像是一个仅能存放一个元素的容器,实现了‘未初始化’的概念:如果元素未初始化,那么容器就是空的,否则容器内就是有效的,已经初始化的值。

optional的类摘要如下:

  template<class T>
  class optional
  {
   public:
      optional();
      optional(none_t );
      optional(T const& v);
      optional(bool condition,T v);
      
      optional& operator= (T const& rhs);
      template<class... Args> void empace ( Args..&& args );
      T* operator->();		//重载操作符
      T* operator *();		
      T& get();				//访问值
      T* get_ptr();
      T& value();
      T const& value_or( T const& defalut ) const ; //
      tmeplate<typename F> T value_or_eval( F f) const;
      explicit operator bool() const;
      bool operator!() const;
  };

用法:
optional的接口简单明了,可以把它认为是一个大小为1且行为类似于指针的容器
基本用法:

    #include <boost/optional.hpp>
    using namespace boost;
    int main()
    {
      optional<int> op0;
      optional<int> op1(none);
      
      assert(!op0);
      assert(op0 == op1);
      
      assert(op1.vlue_or(253) == 253);
      cout<<op1.value_or_eval(
      		[](){return 874;}) <<endl;
      optional<string> ops("test");
      cout<<*ops<<endl;
      
      ops.emplace("monado",3);
      assert(*ops == "mom");
      
      vector<int> v(10);
      optional<vector<int> &> opv(v);
      assert(opv);
      
      opv->push_back(5);
      assert(opv->size() == 11);
      
      opv = none;
      asssert(!opv);
  }