您的位置:首页 > 其它

Boost源码学习三[实用工具](3)

2015-12-01 16:42 369 查看
第三个学的是optional,按照Boost程序库开发指南中的介绍:

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		emplace(Args...&& args);
	T*		operator ->();	
	T&		operator &();
	T&		get();
	T*		get_ptr();
	T&		value();
	T const&		value_or(T const&default)	const;
	template<typename F>
	T	value_or_eval(F f)	const;
	explicit operator bool() const;
	bool operator!() const;
};
optional库使用"容器"语义,包装了"可能产生无效值"的对象,实现了"未初始化"的概念.

#include <boost/optional.hpp>

using namespace boost;

"无意义"的值:

函数并不总能返回有效的返回值,很多时候函数可能返回"无意义"的值,这不意味着函数执行失败,而是表明函数正确执行了,但结果却不是有用的值。

表示返回值无意义最常用的做法是增加一个"哨兵"的角色,它位于解空间之外,如NULL,-1,EOF,string::npos,vector::end()等。但这些做法不够通用,而且很多时候不存在解空间之外的"哨兵".

optional使用"容器"语义,为这种"无效值"的情形提供了一个较好的解决方案。

optional很像一个仅能存放一个元素的容器,它实现了"未初始化"的概念:如果元素未初始化,那么容器就是空的,否则,容器内就是有效的,已经初始化的值。

optional的真实接口很复杂,因为它要能够包装任何的类型。

操作函数:

optional的模板类型参数T可以使任何类型,就如同一个标准容器对元素的要求,并不需要T具有缺省构造函数,但必须是可拷贝构造的。

可以有很多方式创建optional对象,例如:

【1】无参的optional()或者optional(boost::none)构造一个未初始化optional对象,参数boost::none是一个类似空指针的none_t类型常量,表示未初始化;

【2】optional(v)构造一个已初始化的optional对象,其值为v的拷贝。如果模板类型为T&,那么optional内部持有对引用的包装;

【3】optional(condition, v)根据条件condition来构造optional对象,如果条件成立(true)则初始化为v,否则为未初始化;

【4】此外optional还支持拷贝构造和赋值操作,可以从另一个optional对象构造。当想让一个optional对象重新恢复到未初始化状态时,可以向对象赋none值;

optional采用了指针语义来访问内部保存的元素,这使得optional未初始化时的行为就像一个空指针。它重载了operator*和operator->以实现与指针相同的操作,get()和get_ptr()可以以函数的操作形式获得元素的引用和指针。

成员函数get_value_or(default)是一个特别的访问函数,可以保证返回一个有效的值,如果optional已初始化,那么返回内部的元素,否则返回default。

optional也可以用隐式类型转换进行bool测试(用于条件判断),就像一个队指针的判断。

optional还全面支持比较运算,包括==,!=,<,<,>,>=。与普通指针比较的"浅比较"(仅比较指针值)不同,optional的比较是"深比较",同时加入了对未初始化情况的判断。

用法:

#include <type_traits>
#include <std.hpp>
using namespace std;

#define BOOST_DISABLE_ASSERTS
#include <boost/optional.hpp>
using namespace boost;
//////////////////////////////////////////
void case1()
{
    cout << typeid(none).name() << endl;
    cout << std::is_member_object_pointer<none_t>::value << endl;
}
//////////////////////////////////////////
void case2()
{
    optional<int> op0;
    optional<int> op1(none);

    assert(!op0);
    assert(op0 == op1);
    assert(op1.value_or(253) == 253);

    cout << op1.value_or_eval(
            [](){return 874;}) << endl;

    optional<string> ops("test");
    cout << *ops << endl;

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

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

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

    opv = none;
    assert(!opv);
}

//////////////////////////////////////////
optional<double> calc(int x)
{
    return optional<double>( x != 0, 1.0 / x);
}

optional<double> sqrt_op(double x)
{
    return optional<double>(x > 0, sqrt(x));
}

void case3()
{
    optional<double> d = calc(10);

    if (d)
    {
        cout << *d << endl;
        cout << d.value() << endl;
    }

    d = sqrt_op(-10);
    if (!d)
    {   cout << "no result"<< endl; }
}

//////////////////////////////////////////
void case4()
{
    auto x = make_optional(5);
    assert(*x == 5);

    auto y = make_optional<double>((*x > 10), 1.0);
    assert(!y);
}
//////////////////////////////////////////
int main()
{
    case1();
    case2();
    case3();
    case4();
}



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: