Yes? No? Maybe? (Part I)

Initializing arrays, or any variable for that matter, is always kind of a problem. Most of the times, you can get away with a default value, typically zero in C#C++, but not always. For floats, for example, NaN makes much more sense. Indeed, it’s initialized to not a number: it clearly states that it is initialized, consciously, to not a value. That’s neat. What about integers? Clearly, there’s no way to encode a NaI (not an integer), maybe std::numeric_limits::min(), which is still better than zero. What about bools?

Bool is trickier. In C++, bool is either false or true, and weak typing makes everything not zero true. However, if you assign 3 to a bool, it will be “normalized” to true, that is, exactly 1. Therefore, and not that surprisingly, you can’t have true, false, and maybe. Well, let’s fix that.

The obvious choice is to define an enum class that (redefines) false, true, and undefined (the not-a-bool). But we can’t refine true and false directly because they are keywords (at least in C++… not so sure in C). So we’ll need to have a (normal) class around that enum class to deal with states and operators.

template <typename storage=int>
class _trool
 {
  public:

      // anonymous enum class with storage?
      using __trool=enum : storage { undefined=0, _false=1, _true=2 };

      __trool state;

  _trool operator=(bool x) { state=x?_true:_false; return *this; }

  operator char() const { return "uft"[state]; } // because I can.

  operator bool() const
   {
    if (state==undefined)
     throw std::bad_cast();
    else
     return (state==_true);
   }

  _trool(): state(undefined) {}
  _trool(int s): state(s==0?undefined:(s==1?_false:_true)) {}
  _trool(bool s): state(s?_true:_false) {}
  ~_trool()=default; // nothin' much to do
 };

using trool=_trool<>; // defaults

Since C++11, we can not only declare strongly-typed enum classes, but also specify their storage—what kind of integers to use to store the enumerated values. What surprised me is that you can specify storage on an anonymous enum. For all kind of performance-related reasons, enum storage seems to default to int, which is what I’ve implemented here. Well, to be more precise, I implemented a class that accepts a storage type, but also an alias to its default, int.

*
* *

The problem with this implementation is that it won’t play very well with std::vector. As you know, there’s an explicit specialization, std::vector<bool> that uses one bit per bool rather than whatever is the default storage. But we still can use very efficient storage for this tri-state bool thingie.

To be continued…

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: