I think std::bitset<N> provides most of the functionality you want
here. You'd define a normal enum class with contiguous values, and
you'd use the bitset type for sets of such enums. With the
std::max_enumeration_value<type> you suggest, one could easily write
an enum_set<enum_t> which deduces the proper N for a bitset.
On Jul 22, 2013 12:26 AM, "Sean Middleditch" <se...@middleditch.us> wrote:
> Again, I'm all for library-only solutions. QFlags ain't it.
> std::bitset fails due to not using the type system at all (nothing
> stops you from accidentally combining flags1::value with flags2::value
> into the same bitset, and there's other issues involving how you'd
> define "combined flag" constants in an obvious clean way). Pasting
> together operator overloads for every set of flags is repetitive and
> error-pone.
Recall that I suggested an enum_set<enum_t> given an extension for reflecting enum values, not just a raw bitset. It'd be easy to make enum_set <enum_t>'s operator[] take an enum_t and not just an int. With today's language you'd define combined constants with
auto combined = make_enum_set(value1) | make_enum_set(value2);
Or possibly make_enum_set(value1, value2) if the library wanted.
With the language extension I mentioned to define conversion operators, I suspect you could just use "value1 | value2".
QFlags represents the best you can do now, which is exactly what I was
getting at as a nasty workaround. I already know how to handle flags
today; I'm not exactly new at this game. :)
** QFlags and its ilk is the problem I'd like to solve here, not the
solution. **
Macros,
no proper scoping of values,
doesn't use the new C++11 enum classes,
can't be used with forward-declared enums,
// usestruct my_flags_tag;using my_flags = flags<int, my_flags_tag>;template<> enum my_flags::type : int {none = 0,first = 0x1,second = 0x2,third = 0x4};
On Monday, July 22, 2013 12:14:29 PM UTC-7, Richard Smith wrote:// usestruct my_flags_tag;using my_flags = flags<int, my_flags_tag>;template<> enum my_flags::type : int {none = 0,first = 0x1,second = 0x2,third = 0x4};I had absolutely no idea this kind of use of forward-declared enums in templates was legal, but in retrospect, it seems obvious. Excellent. What would use of this type look like?auto foo = my_flags::type::second; // is that 'type' necessary there?
Following up then, is there maybe a call for the constexpr helpers mentioned earlier being in the standard library? std::bit, std::next_power_of_two/std::next_bit, etc (with better names of course). Some of these are super trivial to just write (like a constexpr bit), but others are just enough code to get obnoxious even with C++14 constexpr if I had to rewrite for every sample, helper library, and so on (like constexpr next_next_of_two).