Snorlax
Snorlax

Reputation: 827

How to have a tri-state 'boolean' in c++

What is the best way to have three value Boolean variable in c++?

I would like to have fields set to true, false or not set at all in my array.

If I declare them this way:

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

When I test the condition I get:

t[2] is false

Upvotes: 9

Views: 16250

Answers (7)

Michail Alexakis
Michail Alexakis

Reputation: 1585

I also believe an enum declaration is the cleaner and simplest solution.

A small note on the size of the new type: enums are usually (depending of course on the compiler) backed by integers, so you are allocating something like 32 or 64 bits to actually use 2 bits.

In newer C++ (C++11), you can specify the underlying type of the enum (to an existing integral type). For example:

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

Upvotes: 2

Status3543
Status3543

Reputation: 1277

This should work:

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

Or if you only need 3 states but perhaps would like more at some point, an enum is great:

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

No matter what though, 0/false is the only thing that returns false in an if() statement. -1 and true both return true.

You may want to use a switch like this to deal with 3+ states:

switch (var)    // may need to cast: (int)var
{
case 1:
case 0:
case -1:
};

Alternatively if you want to stick to an if statement block, you could do something like this:

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

Upvotes: 6

Andreas DM
Andreas DM

Reputation: 10998

You can use std::optional for this:

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';

output:

1
0

Upvotes: 5

ABaumstumpf
ABaumstumpf

Reputation: 297

What is the best way to have three value Boolean variable in c++?

Boolean values by definition only have 2 possible states - True or False. If you want to have another state for 'invalid' or 'not set' then you need to encapsulate the bool variable in some other data-types.

The right solution depends on what you want to do with that variable. For simple comparisons (if-else and switch) scoped enums (c++11) should be preferred.

enum class tristate{true,false,undefined=0};

They are simple, easy to use and understand and offer type safety over plane old enums. As they are type-safe you can not accidentally compare it with different types of enums or numeral types, But it also means you can not use bitfiddling and integer-tricks either. Unless a different type is specified an enum class is a numerical type which gets initialized to '0'. that means by assigning the value '0' to one of the enum-values you can make that the default state.

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

Of course you can use that in a switch-statement:

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

Upvotes: 3

Bathsheba
Bathsheba

Reputation: 234685

Consider using std::experimental::optional<bool> (if your C++ standard library has it), or boost::optional<bool> (www.boost.org).

I believe std::optional is a candidate for C++17 so if you adopt one of the above then your refactoring effort to C++17 ought to be minimal.

If you don't like using things that are not (yet?) in the "proper" C++ standard library, then consider

  1. Something based around std::unique_ptr<bool>

  2. A std::pair<bool, bool>

  3. A good old-fashioned enum with 3 values.

Upvotes: 6

Juan Leni
Juan Leni

Reputation: 7588

You could use boost::optional

http://www.boost.org/doc/libs/1_60_0/libs/optional/doc/html/index.html

boost::optional<bool> myBooleanVariable;

I agree that tribool can be better if you don't need the uninitialised values to be NULL. Where comparing optional and tribool, the documentation says:

First, it is functionally similar to a tristate boolean (false, maybe, true) —such as boost::tribool— except that in a tristate boolean, the maybe state represents a valid value, unlike the corresponding state of an uninitialized optional. It should be carefully considered if an optional instead of a tribool is really needed.

Source: http://www.boost.org/doc/libs/1_60_0/libs/optional/doc/html/boost_optional/a_note_about_optional_bool_.html

Upvotes: 3

H. Guijt
H. Guijt

Reputation: 3365

You might want to look at boost.tribool: http://www.boost.org/doc/libs/1_60_0/doc/html/tribool.html

Upvotes: 8

Related Questions