
On 23.03.2017 01:40, Andrey Semashev via Boost wrote:
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); } };
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.
Using std::bitset in this way is not a good solution. C++ standard doesn't claim that bitset's backing storage should be as compact as possible. In stdlibc++ bits are stored in array of unsigned long items. So on my Ubuntu x64 sizeof(typed_bitset< animal_traits, animal_traits::_count >) == 8 That's not acceptable for only 3 bits. Another problem is that member functions for bit manipulations are not marked as *noexcept*. Using weak enum-based parameterization you can be sure in proper use bits. But the compiler doesn't know it. That's why I've come to making my own container. I need compact storage and noexcept guarantee at compile time.