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);
}