Boost logo

Boost :

Subject: Re: [boost] Is there any interest in type-safe container of bool flags with noexcept guarantees?
From: Roman Orlov (compmaniak_at_[hidden])
Date: 2017-03-22 16:02:05


On 21.03.2017 21:23, Steven Watanabe via Boost wrote:
>
> what's wrong with
> struct animal {
> bool eats_meat : 1;
> bool eats_grass : 1;
> bool has_tail : 1;
> };
>

There are several reasons I don't like that approach

While declaring a variable of type 'animal' you should always keep in
mind to initialize it with empty initializer
   animal a1; // bit fields are not initialized
   animal a2{}; // now it's ok, bits are set to zeros

When you want to initialize some fields (eats_grass, has_tail) you have
to write several lines of code
   animal a1{};
   a1.eats_grass = 1;
   a1.has_tail = 1;

Of course, it can be done in one line with initializer list
   animal a1{0, 1, 1};

But we don't write a code ones, we are about to support it for a long
time. One day we decided to add a new bit field to structure
   struct animal {
     bool can_fly : 1; // yeah, somebody puts it on the first position
     bool eats_meat : 1;
     bool eats_grass : 1;
     bool has_tail : 1;
   };

What will happen with all of list initializers? There will be bugs we
can't detect at compile time.
   animal a1{0, 1, 1}; // now it doesn't work properly

We have to find all of such initializers and rewrite them
   animal a1{0, 0, 1, 1};

To prevent this I propose to abstract from strict ordering and use
typed entities
   animal a1{flag<eats_grass>{1}, flag<has_tail>{1}};

And what about bitwise operations on plain structures? While working
with bool properties conjunction and disjunction are needed fairly
often. For each structure you'll have to implement them manually.
Of course it's better to have it out of the box
   auto a1 = animal{flag<eats_gass>{1}} | animal{flag<eats_meat>{1}};

Sometimes it's needed to test that all flags are set or at least one.
And again for each structure you'll have to implement it manually.
It's better to have these functions in container
   auto a1 = animal{flag<eats_gass>{1}};
   assert( (!a1.all()) );
   assert( (!a1.any<eats_meat, has_tail>()) ); // with some syntax sugar

Managing typed entities allows you to test common properties of
semantically different entities. For example:
   class p1;
   class p2;
   class p3;
   class p4;

   typedef typed_flags<p1, p2, p3> a; // has p3 property
   typedef typed_flags<p3, p4> b; // has p3 property too

   template<typename T, typename... Args>
   bool test_p(Args&&... args) {
     return (... && args.template test<T>());
   }
   // test p3 property from a and b
   test_p<p3>(a{flag<p3>{1}}, b{flag<p3>{1}});


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk