boost:tribool

1059 篇文章 286 订阅

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

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

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

类摘要

在这里插入图片描述

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

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

不确定状态indeterminate是一个特殊的tribool值,它与bool值true、false的运行遵循三态布尔逻辑:
在这里插入图片描述
自由函数indeterminate()可以判断一个tribool是否出于不确定状态。

用法

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

#include <iostream>
#include <assert.hpp>

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


int main() {  
   tribool tb(true);   // 值为true的tribool
   tribool tb2(!tb);

   if(tb){
       printf("true\n");   // 输出true
   }

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

   if (tb2 == indeterminate){   // 与indeterminate比较,无意义
       printf("indeterminate\n");  //不会输出
   }

    if (indeterminate(tb2)){  // 用indeterminate()函数检测状态
        printf("indeterminate()\n"); // 输出indeterminate()
    }

    printf("%d\n", (tb2 || true));  // 逻辑或状态,输出1
    
    return 0;
}

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

#include <iostream>

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


int main() {
   tribool tb(indeterminate);


   if (tb == indeterminate){
       printf("new reach there\n");
   }
    if (tb){
        printf("new reach there\n");
    }
    if (!tb){
        printf("new reach there\n");
    }
    if (indeterminate(tb)){
        printf("indeterminate()\n");
    }

    return 0;
}

为第三态更名

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允许把interminate改变成任意用户喜欢的名字,比如unknown,maybe等。

只需要在全局域中使用宏BOOST_TRIBOOL_THIRD_STATE就可以为第三态更名:

#include <iostream>
#include <assert.h>
#include <boost/logic/tribool.hpp>
using namespace boost;

BOOST_TRIBOOL_THIRD_STATE(unknown);
int main() {
    tribool tb(unknown);   //可以作为不确定值
    assert(unknown(tb));   // 可以作为检测函数
    assert(unknown(tb || false));
    return 0;
}

宏只是定义了一个新的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);
};

BOOST_TRIBOOL_THIRD_STATE(tmp_ns::unknown);

输入输出

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

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

int main() {
    tribool tb1(false), tb2(true), tb3(indeterminate);

    std::cout << tb1 << ", " << tb2 << ", " << tb3;  // 0, 1, 2

    return 0;
}

其他

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

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

int main() {
    optional<bool> b;    //b未经初始化,既不是true也不能false
    if (!b){
        printf("interminate\n");
    }

    b = false;
    if(b){                    //b有值false
        printf("b=%d\n", *b);   //输出b=0
    }

    return 0;
}

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

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


optional<bool> b(false);

// 错误写法
if(!b){   // option的bool转换
	printf("false\n");
}

//正确写法
if(b && *b){
		printf("false\n");
}

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值