I'm trying to create a flags bitfield using C++11 enum classes. I'm looking for a way to templatize the operators' return types so they can be used as in code below:
#include <iostream>
enum class Flags {
one = 1,
two = 1 << 1,
three = 1 << 2,
four = 1 << 3
};
#define _CONVERT(_operator) \
static_cast<T>(static_cast<int>(lhs) _operator static_cast<int>(rhs))
template <typename T>
T operator & (const Flags& lhs, const Flags& rhs) {
return _CONVERT(&);
}
template <typename T>
T operator | (const Flags& lhs, const Flags& rhs) {
return _CONVERT(|);
}
#undef _convert
int main()
{
Flags flag = Flags::one | Flags::two | Flags::three;
if (flag & Flags::two)
std::cout << "Flag has two" << std::endl;
if (flag & Flags::four)
std::cout << "Flag has four" << std::endl;
std::cout << static_cast<int>(flag) << std::endl;
}
However, there are several problems:
Flags flag = Flags::one | Flags::two | Flags::three;
can't deduce type to beFlags
if (flag & Flags::four)
can't deduce type to bebool
I'm new to templates and am kinda lost when it comes to template deduction mechanisms. Also, i tried to create create conversion operator
operator bool(const Flags& flag)
but with no result.
First create a helper template:
Next, create a trait function and type:
Now
magic_operators::use_algebra<E>
searches using ADL foralgebraic_enum
overload returningstd::true_type
onE
. This permits enabling the magic anywhere. MSVC 2015 lacks sufficient C++11 support to use the above; replace with traits class.The meat: our operators. Stick them into a namespace and bring them in with
using namespace
:And similar for
|
.For
~
and^
you need a bit mask to remain defined behaviour. Have a traits classenum_mask<E>
that defaults toE::bit_mask
or somesuch to get it.This is tricky due to standards requirements on out of gamut enums.
|=
and&=
isn't hard, but does need to be coded.=
and|=
and&=
etc that support both assignment chaining and implicit bool requires yet more work. I say do not support it.Oh and mark everything
constexpr
and addbool_or_enum<E>
overloads to theoperator
s.The above code is not tested or compiled, but the design works.
The end result is:
Or somesuch.