A
Ich bin jetzt nach ein paar Iterationen bei folgendem Design angekommen:
template <typename FlagsT, typename UnderlyingTypeT = unsigned>
struct DefineFlags
{
enum class Flags : UnderlyingTypeT { None = 0 };
using Flag = Flags;
friend constexpr Flags operator |(Flags lhs, Flags rhs) noexcept { return Flags(UnderlyingTypeT(lhs) | UnderlyingTypeT(rhs)); }
friend constexpr Flags operator &(Flags lhs, Flags rhs) noexcept { return Flags(UnderlyingTypeT(lhs) & UnderlyingTypeT(rhs)); }
friend constexpr Flags operator ^(Flags lhs, Flags rhs) noexcept { return Flags(UnderlyingTypeT(lhs) ^ UnderlyingTypeT(rhs)); }
friend constexpr Flags operator ~(Flags arg) noexcept { return Flags(~UnderlyingTypeT(arg)); }
friend constexpr Flags& operator |=(Flags& lhs, Flags rhs) noexcept { lhs = lhs | rhs; return lhs; }
friend constexpr Flags& operator &=(Flags& lhs, Flags rhs) noexcept { lhs = lhs & rhs; return lhs; }
friend constexpr Flags& operator ^=(Flags& lhs, Flags rhs) noexcept { lhs = lhs ^ rhs; return lhs; }
friend constexpr bool hasFlag(Flags flags, Flag flag) noexcept { return (UnderlyingTypeT(flags) & UnderlyingTypeT(flag)) != 0; }
friend constexpr bool hasAny(Flags flags, Flag flag) noexcept { return (UnderlyingTypeT(flags) & UnderlyingTypeT(flag)) != 0; }
friend constexpr bool hasAll(Flags flags, Flag flag) noexcept { return Flags(UnderlyingTypeT(flags) & UnderlyingTypeT(flag)) == flag; }
};
Benutzung:
struct Gemüse : DefineFlags<Gemüse>
{
static constexpr auto Sellerie = Flag(1);
static constexpr auto Karotten = Flag(2);
static constexpr auto Porree = Flag(4);
static constexpr auto Kartoffeln = Flag(8);
static constexpr auto Spargel = Flag(16);
};
using Gemüsesuppe = Gemüse::Flags;
Das ist einerseits schöner, weil man jetzt Gemüse::Sellerie schreibt und nicht Gemüsesuppe::Sellerie , andererseits ist Gemüsesuppe jetzt einfach ein Enumerator, womit die o.g. odr-use-Problematik wegfällt. Außerdem kann ich Gemüsesuppe jetzt auch in switch -Statements verwenden:
bool inSpeisekarte(Gemüsesuppe suppe)
{
switch(suppe)
{
case Gemüse::Spargel: // "...und als Vorspeise nehm ich die smackhafte Spargelcremesuppe bitte!"
return true; // "Sehr gern."
case Gemüse::Karotten:
case Gemüse::Kartoffeln | Gemüse::Porree:
return true;
default:
return false;
}
}
Edit: kleine Korrekturen