The bit flag or bit mask is a recurring topic in the C++ community. Since enum class has been added, the attempt to create a more type-safe and/or easier-to-use bit flag has never ended. It never succeeded either, as all solutions were flawed in some ways that they've never beaten the straightforward enum . Some define bitwise-operators for enum class but use additional macros or specializations, while still requiring manually defined power-of-2 values. Some others create a wrapper class, but lost the capability to express the flag with combination of enum literals. With several features coming to C++20, I'd like to explore another possible design.

struct AnimationFlag { bool FullMatch : 1 = false; //initialization is optional here bool PlayForever : 1 = false; bool NonLooping : 1 = false; }; // usage AnimationFlag f { .FullMatch = true, .NonLooping = true };

From memory layout point of view, a flag value is rather a (mis)interpretation of an offset in the bit field. Even though bit field always existed in C++, now the difference is that with Designated initializer, we can actually define it with a single, clean statement. In the example above, .FullMatch and .NonLooping are initialized to 1 whereas all others to 0 . If you want to absolutely make sure value is always 0-initialized, Bit field member in-class initialization is helpful albeit more verbose.

Now, is it good enough for production? Considering several use cases -

Composing a mask from both positive and negative flags: f = a | b or f = all & ~c

or Determining if a flag is on or off: (f & a) != 0

Manipulating flags: f |= (a | b) or f ^= c

In our case, determining or manipulating a single flag is trivial. However, it's still missing the expression support - combining flags with bitwise operators (preferably 0-cost and supports constexpr ) is an important part of the design. We can overload operator |, &, ^ for a generic type T and only allow "our types" by using SFINAE, but it's a really dangerous decision due to the potential conflict with other generic overloads in 3rd-party libraries, and the huge impact on compilation time.

In C++20 we are finally going to have Concepts, although at this point it's unclear how much build time advantage it provides.

//credit https://stackoverflow.com/questions/39768517/structured-bindings-width struct filler { template< typename type > operator type (); }; template< typename aggregate, typename index_sequence = std::index_sequence<>, typename = void > struct aggregate_arity : index_sequence { }; template< typename aggregate, std::size_t ...indices > struct aggregate_arity< aggregate, std::index_sequence< indices... >, std::void_t< decltype(aggregate{(indices, std::declval< filler >())..., std::declval< filler >()}) > > : aggregate_arity< aggregate, std::index_sequence< indices..., sizeof...(indices) > > { }; template< typename aggregate > constexpr std::size_t get_aggregate_arity() { return aggregate_arity< std::remove_reference_t< std::remove_cv_t< aggregate > > >::size(); } template<typename T> struct always_false : std::false_type {}; struct flag{}; template<typename T> requires std::is_base_of_v<flag, T> constexpr T operator& (T a, T b) { constexpr std::size_t arity = get_aggregate_arity<T>(); if constexpr (arity == 2/*empty base takes 1*/) { auto [a1] = a; auto [b1] = b; return T {{}, a1&b1}; } else if constexpr (arity == 3) { auto [a1,a2] = a; auto [b1,b2] = b; return T {{}, !!(a1&b1), !!(a2&b2)}; } else if constexpr (arity == 4) { auto [a1,a2,a3] = a; auto [b1,b2,b3] = b; return T {{}, !!(a1&b1), !!(a2&b2), !!(a3&b3)}; } else if constexpr (arity == 5) { auto [a1,a2,a3,a4] = a; auto [b1,b2,b3,b4] = b; return T {{}, !!(a1&b1), !!(a2&b2), !!(a3&b3), !!(a4&b4)}; } //all the way up to 32 or 64 ... else { static_assert(always_false<T>::value, "not supported"); return T{}; } }

In order to support arbitrary length and constexpr for the bit flag, we can't reinterpret_cast the underlying memory or use type punning (UB!). That's where structured binding kicks in - although the implementation is tedious due to the lack of variadic structured binding.

struct AnimationFlag : flag { bool FullMatch : 1; // = 0 is optional bool PlayForever : 1; bool NonLooping : 1; }; constexpr AnimationFlag f = {.FullMatch = true, .PlayForever = true}; constexpr AnimationFlag f2 = f & ~AnimationFlag{.FullMatch = true}; static_assert(!f2.FullMatch && f2.PlayForever && !f2.NonLooping);

I'd say this is equivalent or better than macro / const / enum based bit flags because

It doesn't require defining and maintaining power-of-two values

It's type safe

It supports any number of flags

What do you think?