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 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 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 op0;
optional op1(none);

assert(!op0);
assert(op0 == op1);

assert(op1.vlue_or(253) == 253);
cout<<op1.value_or_eval(
) <<endl;
optional ops("test");
cout<<*ops<<endl;

ops.emplace("monado",3);
assert(*ops == "mom");

vector v(10);
optional<vector &> opv(v);
assert(opv);

opv->push_back(5);
assert(opv->size() == 11);

opv = none;
asssert(!opv);
}