Boost开发指南-4.7tribool

tribool

boost.tribool类似c++内建的bool类型,但基于三态的布尔逻辑:在true(真)和false(假)之外还有一个indeterminate状态(未知、不确定)。一个例子场景是执行某项任务,在执行之前状态是未知的(没有开始也没有结束),启动任务后状态是 true,停止任务后状态是false。

tribool位于名字空间boost::logic,但为了方便使用被using语句引入了boost名字空间,为使用tribool组件,需要包含头文件<boost/logic/tribool.hpp>,即

#include <boost/logicltribool.hpp>
using namespace boost;

类摘要

class tribool
{
    
    
public:
   tribool(bool value); //缺省构造函数
   tribool(bool initial_value); //bool值构造函数
   tribool (indeterminate_keyword_t); //初始化为不确定值
   operator safe_bool() const; //bool转型
   enum value_t {
    
     false_value,true_value,indeterminate_value } value;
};
bool indeterminate (tribool x); //判断是否是不确定状态
tribool operator!(tribool x);
... //其他逻辑运算符和比较运算符重载

tribool 类很简单,它内部实现了三态 bool值的表示,除了构造函数没有什么其他成员函数。可以在创建tribool对象的同时传入三态bool值对它进行初始化,如果使用无参的缺省构造函数,那么tribool默认值是false。

对tribool的操作都是通过逻辑运算符和比较运算符的重载来完成的,支持的逻辑运算包括||、&&和!,比较运算支持== 和 !=,这些操作都可以任意混合bool和tribool一起运算。

不确定状态indeterminate是一个特殊的tribool值,它与bool值 true、false的运算遵循三态布尔逻辑:
1)任何与indeterminate的比较操作结果都是indeterminate;
2)与indeterminate 的逻辑或运算(||)只有与true运算结果为true,其他均为indeterminate;
3)与indeterminate的逻辑与运算(&&)只有与false运算结果为false,其他均为indeterminate;
4)indeterminate 的逻辑非操作(!)结果仍为indeterminate。

用法

tribool可以像普通的bool类型一样使用,只是多出了一个indeterminate(未知、不确定)的取值。如果仅使用true和 false两个值,那么tribool与 bool的用法是完全相同的,但如果需要使用indeterminate值,就必须遵循三态布尔的逻辑运算规则。

#include <boost/logic/tribool.hpp>
using namespace boost;
int main()
{
    
    
	tribool tb(true); //值为true的tribool
	tribool tb2(!tb); //值为false

	if (tb) //tb==true
	{
    
    
		cout << "true" << endl;
	}

	tb2 = indeterminate; //tb2是不确定状态
	assert(indeterminate(tb2)); //用indeterminate函数检测状态
	cout << "tb2 = " << tb2 << endl;

	if (tb2 == indeterminate) //与indeterminate值比较,无意义
	{
    
    
		cout << "indeterminate" << endl; //这行语句不会执行
	}

	if (indeterminate(tb2)) //用indeterminate函数检测状态
	{
    
    
		cout << "indeterminate" << endl; //输出"indeterminate"
	}

	cout << (tb2 || true) << endl; //逻辑或运算,输出true
	cout << (tb2 && false) << endl; //逻辑与运算,输出false
}

在处理tribool的不确定状态时必须要小心,因为它既不是true也不是false,使用它进行条件判断永远都不会成立,判断不确定状态必须要使用indeterminate()函数:

tribool tb(indeterminate);

if (tb) //永远不成立
	cout << "never reach here" << endl;
if (!tb) //永远不成立
	cout << "never reach here" << endl;

if (indeterminate(tb)) //必须使用indeterminate
	cout << "indeterminate" << endl;

为第三态更名

tribool 的第三态类型indeterminate_keyword_t实际上是一个函数指针类型:

typedef bool(*indeterminate_keyword_t) (tribool,detail::indeterminate_t);

而indeterminate实际上只是一个符合indeterminate_keyword_t类型的函数,它的真正功能是用来判断tribool对象内部值是否是第三态,但在tribool的构造函数里被当做一个标志,只要是indeterminate_keyword_t类型那么就置为不确定状态:

tribool(indeterminate_keyword_t) : //构造函数,接受特殊的参数
           value (indeterminate_value){
    
    } //置为不确定状态

作为第三态的名字 indeterminate很清晰明确但可能有些长,所以 tribool 允许把indeterminate改变成任意用户喜欢的名字,常用的名字可以是 unknown、maybe、true_or_false等。

只需要在全局域内使用宏BOOST_TRIBOOL_THIRD_STATE就可以为第三态更名,像这样:

BOOST_TRIBOOL_THIRD_STATE(unknown)

然后我们就可以随意使用这个新名字代替原来的indeterminate:

tribool tb(unknown); //可以作为不确定值
assert(unknown(tb)); //可以作为检测函数
assert(unknown(tb || false));

宏BOOST_TRIBOOL_THIRD_STATE只是定义了一个新的indeterminate_keyword_t类型的函数而已,类似于:

inline bool some_name(tribool x)
{
    
     return x.value == tribool::indeterminate_value; }

因为宏 BOOST_TRIBOOL_THIRD_STATE实质上定义了一个函数,而C++不允许函数嵌套,所以这个宏最好在全局域使用,它将在定义后的整个源代码中都生效。

如果把 BOOST_TRIBOOL_THIRD_STATE 用在一个名字空间里,那么新的第三态名字将成为名字空间的一个成员,使用时需加上名字空间限定,例如:

namespace tmp_ns //一个临时名字空间
{
    
    
    BOOST_TRIBOOL_THIRD_STATE(unknown)
};
tribool tb (tmp_ns::unknown); //使用名字空间限定

输入/输出

tribool可以如 bool类型一样进行流操作,但需要包含另外一个头文件<boost/logic/tribool_io.hpp>

只要包含了这个头文件,就可以使用>>、<<操作符向cin、cout等流对象输入/输出,false、true和 indeterminate分别对应整数0、1和2。如果设置了流的 boolalpha标志,则对应字符串"false"、“true"和"indeterminate”。

#include<boost/logic/tribool_io.hpp>
using namespace boost;
int main()
{
    
    
    tribool tb1(true),tb2(false),tb3(indeterminate);
    cout << tb1 << "," //输出1
         << tb2 << "," //输出0
         << tb3 << endl; //输出2
}

optional<bool>的区别

optional<bool>在功能上有些类似tribool,一个未初始化的optional<bool>同样可以表示不确定的bool值,例如:

optional<bool> b;
if(!b) //b未初始化,既不是true也不是false
{
    
     cout << "indeterminate" << endl; }

b = false;
if(b) //b有值false
{
    
     cout << "b=" << *b << endl; } 

optional<bool>的语义是未初始化的 bool,是无意义的值,而 tribool 的indeterminate是已经初始化的有意义值,它表示bool值不确定。这两者存在着细微但十分重要的差别。

此外,两者的使用方法也存在差别。optional<bool>需要使用类似指针的方式访问容器内的bool值,而tribool可以如普通的bool类型一样直接使用,并且支持各种逻辑运算。

由于 optional支持bool转换,用于检测optional是否已经初始化,所以在 bool语境下如果不注意optional 的这个特性很容易导致意外的错误。例如,下面的代码本意是想使用optional内的bool值作为if语句的判断条件,但实际上条件判断的是optional未初始化:

optional<bool> b(false);
if(!b) //optional的bool转换
{
    
     cout << "false" << endl; }

正确的写法应该是

if(b && !*b) //b已经初始化且值为false
{
    
     cout << "false" << endl; } 

选择 optional<bool>还是tribool需要由代码的具体需求来决定。如果返回值可能是无效的(不存在有效的返回值),那么就是optional<bool>;如果返回值总是确定的,但可能无法确定其意义,那么就用tribool。

代码示例

#include <assert.h>
#include <iostream>
using namespace std;

#include <boost/logic/tribool.hpp>
#include <boost/logic/tribool_io.hpp>
using namespace boost;

//
void case1()
{
    
    
	tribool tb(true);
	tribool tb2(!tb);

	if (tb)
	{
    
    
		cout << "true" << endl;
	}

	tb2 = indeterminate;
	assert(indeterminate(tb2));
	cout << "tb2 = " << tb2 << endl;

	if (tb2 == indeterminate)
	{
    
    
		cout << "indeterminate" << endl;
	}

	if (indeterminate(tb2))
	{
    
    
		cout << "indeterminate" << endl;
	}

	cout << (tb2 || true) << endl;
	cout << (tb2 && false) << endl;

}

//
void case2()
{
    
    
	tribool tb(indeterminate);

	if (tb)
		cout << "never reach here" << endl;
	if (!tb)
		cout << "never reach here" << endl;

	if (indeterminate(tb))
		cout << "indeterminate" << endl;
}

//
BOOST_TRIBOOL_THIRD_STATE(unknown)

namespace tmp_ns
{
    
    
	BOOST_TRIBOOL_THIRD_STATE(unknown)
};


void case3()
{
    
    
	tribool tb(tmp_ns::unknown);
	assert(unknown(tb));
	assert(unknown(tb || false));

}

//
#include <boost/optional.hpp>
using namespace boost;

void case4()
{
    
    
	optional<bool> b;

	if (!b)
	{
    
    
		cout << "indeterminate" << endl;
	}

	b = false;
	if (b)
	{
    
    
		cout << "b=" << *b << endl;
	}

	if (!b)
	{
    
    
		cout << "false" << endl;
	}

	if (b && !*b)
	{
    
    
		cout << "real false" << endl;
	}

}

//

int main()
{
    
    
	case1();
	case2();
	case3();
	case4();
}

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_36314864/article/details/132333744