$include_dir="/home/hyper-archives/boost/include"; include("$include_dir/msg-header.inc") ?>
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