如何在C++中实现三态布尔值

8

在C++中,有什么最好的方式来创建一个包含三个值的布尔变量呢?

我希望我的数组中的字段可以设置为truefalse或者不设置。

如果我这样声明它们:

t[0] = true;
t[1] = false;
t[2] = NULL;

当我测试条件时,我得到了以下结果: t[2]false

4
创建一个枚举来包含你的三个值。 - Martin G
快要到了。在一个高效的类中实现{0,1,Z,X}的逻辑运算符将非常有用。Z在boost triclass中映射为“不确定”,也被称为“两者都是”。'X'或不关心是不确定的相反。这是针对逻辑情况的,其中一个值并不重要;它无关紧要。[数据库实现4值逻辑?] - artless noise
7个回答

7

6

这应该可以正常工作:

t[0] = true;
t[1] = false;
t[2] = -1;

如果您只需要3种状态,但可能在某些时候需要更多,那么 enum 很棒:

enum STATES
{
    NULL_STATE = -1,    // you can manually specify -1 to give it a special case value
    FALSE,              // will be equal to 0
    TRUE                // will be equal to 1
};

无论如何,在if()语句中,只有 0/false 返回 false 。-1和true都返回true。您可能想使用以下switch来处理三个或更多状态:
switch (var)    // may need to cast: (int)var
{
case 1:
case 0:
case -1:
};

如果你希望使用if语句块,也可以采用如下方式:

if (var == -1)    // or (var == NULL_STATE)
{}
else if (var)     // true condition
{}
else              // false
{}

5
考虑使用std :: experimental :: optional <bool>(如果您的C ++标准库具有它),或boost :: optional <bool>(www.boost.org)。
我认为std :: optional 是C ++ 17的候选项,因此如果您采用上述方法,则到C ++ 17的重构工作应该是最小的。
如果您不喜欢使用尚未在“正确”的C ++标准库中的内容,则考虑:
1. 基于 std :: unique_ptr<bool>的某些内容 2. std :: pair<bool, bool> 3. 具有3个值的传统 enum 。

4
您可以使用 std::optional 来实现此功能:
std::optional<bool> t[3];

t[0] = true;
t[1] = false;
t[2] = std::nullopt;

for (auto const& i : t)
  if (i.has_value()) std::cout << i.value() << '\n';

输出:

1
0

3
您可以使用boost::optional来实现此功能。
详见http://www.boost.org/doc/libs/1_60_0/libs/optional/doc/html/index.html
boost::optional<bool> myBooleanVariable;

我认为,如果您不需要未初始化的值为NULL,则tribool可以更好。在比较可选和tribool时,文档表示:
首先,它与三态布尔(false,maybe,true)(例如boost :: tribool)功能上类似,但是在三态布尔中,maybe状态表示有效值,而不像未初始化的可选状态。应该仔细考虑是否真正需要一个可选而不是tribool。
来源:http://www.boost.org/doc/libs/1_60_0/libs/optional/doc/html/boost_optional/a_note_about_optional_bool_.html

3
什么是在c++中拥有三个布尔变量的最佳方法?
按定义,布尔值只有两种可能的状态 - 真或假。 如果你想要另外一个状态来表示“无效”或“未设置”,那么你需要将布尔变量封装在其他数据类型中。
正确的解决方案取决于您对该变量的使用目的。 对于简单的比较(if-else和switch),应优先使用作用域枚举(C++11)。
enum class tristate{true,false,undefined=0};

它们简单易用,易于理解,并提供对纯旧枚举的类型安全。由于它们是类型安全的,因此您无法意外地将其与不同类型的枚举或数字类型进行比较,但这也意味着您无法使用位操作和整数技巧。除非指定了不同的类型,否则枚举类是一个初始化为“0”的数字类型。这意味着通过将值“0”分配给其中一个枚举值,您可以使其成为默认状态。

tristatet[7];
t[1] = tristate::true;
t[2] = tristate::false;
t[3] = tristate::undefined;
t[4] = false; //error
t[5] = 0; //error
t[6] = null; //error

t[0] == true; //error
t[0] == tristate::true; // false
t[0] == tristate::undefined; // true

当然,您可以在switch语句中使用它:
switch(t[2]) {
  case tristate::true:
       foo(); break;
  case tristate::false:
       bar(); break; //t[2] was set to tristate::false
  case tristate::undefined :
       doNothing(); break; 
}

2

我认为枚举声明是更加干净和简单的解决方案。

关于新类型大小的一点说明:枚举类型通常(当然取决于编译器)由整数支持,因此您将分配大约32或64位来实际使用2位。

在较新的C ++(C ++ 11)中,您可以指定枚举的基础类型(为现有的整数类型)。例如:

enum tribool: uint8_t {False = 0, True = 1, Unknown = 2};
...
enum tribool f = tribool::False;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接