Boost logo

Boost :

Subject: Re: [boost] Is there any interest in type-safe container of bool flags with noexcept guarantees?
From: Vicente J. Botet Escriba (vicente.botet_at_[hidden])
Date: 2017-03-22 22:54:39


Le 22/03/2017 à 23:40, Andrey Semashev via Boost a écrit :
> On 03/22/17 19:02, Roman Orlov via Boost wrote:
>> 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};
>
> Frankly, all the above problems are solved with constructors.
>
> The only real problem I see with the struct approach is that it's
> lacking expressiveness. From this declaration:
>
> animal a1{0, 1, 1};
>
> it is difficult to immediately say what the value of has_tail will be.
> It would be better if we had named field initialization, like in C,
> but alas.
>
> Usually, I solve this problem with std::bitset with an enum providing
> names for the flags.
>
> enum animal_traits
> {
> eats_meat, eats_grass, has_tail, _count
> };
> typedef std::bitset< animal_traits::_count > animal;
>
> animal a1; // all traits are false
> a1[eats_grass] = 1;
> a1[has_tail] = 1;
>
> I think, this provides the necessary expressiveness and performance. I
> guess, your proposal provides better type safety than this solution,
> but I'm not sure the improvement is significant enough to outweigh the
> more complicated syntax. For example, one could write a slightly more
> complicated version of the above:
>
> enum animal_traits
> {
> eats_meat, eats_grass, has_tail, _count
> };
>
> template< typename Enum, unsigned int Count >
> class typed_bitset :
> public std::bitset< Count >
> {
> public:
> bool operator[] (Enum idx) const
> {
> return std::bitset< Count >::operator[](idx);
> }
> };
>
I have an ordinal_set<Ordinal> that is type safe.
An enum as the previous one canbe see as an Ordinal and so

     enum animal_traits
     {
       eats_meat, eats_grass, has_tail, _count
     };
     using animal_traits_set = ordinal_set<animal_traits>

> typedef typed_bitset< animal_traits, animal_traits::_count > animal;
>
> animal a1; // all traits are false
> a1[eats_grass] = 1;
> a1[has_tail] = 1;
> a1[10] = 1; // error
>
> I suspect it would also be faster to compile.
compile time for ordinal sets would suffer a little bit as we need to
associate at compile time each enumerator to its position (this could be
provided by reflection or by user defined ordinal traits).

Vicente


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