Le 22/03/2017 à 17:02, Roman Orlov via Boost a écrit : Hi, I like the idea.
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; };
Steven is right, your library is kind of a library reflecting the previous structure. As we don't have yet reflection, we need tag types to identify the fields. I would expect that once we have reflection, we could provide a bit mask interface for the previous structure. But we don't have it yet.
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
I believe that this is good, as you could use it as member of POD structures. While I agree that it is good to initialize everything as soon as possible, some times been able to don't initialize is the correct answer. This is C++.
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;
Well I would replace 1 by true ;-) I find this interface clear.
Of course, it can be done in one line with initializer list animal a1{0, 1, 1};
I agree that positional interfaces don't scale well as you show below.
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
{1}, flag {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
{1}} | animal{flag {1}};
Have you considered to use tag classes that provide this kind of flag
arithmetic?
We write the fftag once, but we use them much more times.
auto a1 = animal{eats_gass{1}} | animal{eats_meat{1}};
The definition of a tag is not complex
struct eats_gass : flag
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
{1}}; assert( (!a1.all()) ); assert( (!a1.any ()) ); // with some syntax sugar If you follow bit_set interface it should be
assert( (!a1.any()) );
The last could be
assert( (!a1.any_of
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
a; // has p3 property typedef typed_flags b; // has p3 property too template
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}});
Here we see that having non-member functions could help avoiding the
not-friendly x.template test<T>
template