I am trying to create type safe C++ flags using templates. I also want to distinguish between a flag and flag s (being zero, one or many flags).
The solution below works good, except for EnumFlag<T> operator | (T, T)
EnumFlag<T> operator | (T, T)
which causes all |
-operations on enums to return type EnumFlag
. This breaks lots of code. Any tricks to fix this? In my code I do the following, however hard coding Option
here is not an option. How to make this generic?
EnumFlag<typename std::enable_if<std::is_same<T, Option>::value, T>::type> operator | (T l, T r)
Changing this to...
EnumFlag<T> operator | (T l, T r)
...of cause breaks everything. I would like something like this (not compilabel code). Or any other better idea!
EnumFlag<typename std::enable_if<std::already_expanded<EnumFlag<T>>::value, T>::type> operator | (T l, T r)
Complete compilable code:
EnumFlag.h
#ifndef __classwith_flags_h_
#define __classwith_flags_h_
#include <type_traits>
enum class Option
{
PrintHi = 1 << 0,
PrintYo = 1 << 1,
PrintAlot = 1 << 2
};
template <typename T>
class EnumFlag
{
public:
using UnderlayingType = typename std::underlying_type<T>::type;
EnumFlag(const T& flags)
: m_flags(static_cast<UnderlayingType>(flags))
{}
bool operator & (T r) const
{
return 0 != (m_flags & static_cast<UnderlayingType>(r));
}
static const T NoFlag = static_cast<T>(0);
private:
UnderlayingType m_flags;
};
template<typename T>
EnumFlag<typename std::enable_if<std::is_same<T, Option>::value, T>::type> operator | (T l, T r)
{
return static_cast<T>(static_cast<typename EnumFlag<T>::UnderlayingType>(l) | static_cast<typename EnumFlag<T>::UnderlayingType>(r));
}
class ClassWithFlags
{
public:
using Options = EnumFlag < Option >;
void doIt(const Options &options);
};
#endif
EnumFlag.cpp
#include "EnumFlag.h"
#include <iostream>
void ClassWithFlags::doIt(const Options &options)
{
if (options & Option::PrintHi)
{
std::cout << "Hi" << std::endl;
}
if (options & Option::PrintYo)
{
std::cout << "Yo!" << std::endl;
}
}
int main()
{
ClassWithFlags classWithFlags;
classWithFlags.doIt(Option::PrintHi | Option::PrintAlot);
}
> DEMO <
The actual code will contain a lot more operators, however this is enough to illustrate the problem.
One less intrusive solution is this (but still too intrusive)
template<typename T>
typename std::underlying_type<T>::type operator | (T l, T r)
{
return (static_cast<typename std::underlying_type<T>::type>(l) | static_cast<typename std::underlying_type<T>::type>(r));
}
Not god enough, then EnumFlag(const std::underlying_type<T> &flags)
must exist and I lose type safty. Also, I would like for the global operator overloads to only be created for the types actually needed. Macros is also no god because I want ta allow declaration of EnumFlag
s inside classes. The global overloads can not be there, hence I need two macros calls at different locations to create on EnumFlag
.
The solution must be pure C++11/stl.
Anthony Williams have a good acticle with ready code: "Using Enum Classes as Bitfields" .
Maybe it's just what youre looked for. In difference from other solutions which I saw, macroes aren't used here - just pure templates.
Simple example demonstrating his solution:
#include "bitmask_operators.hpp"
enum class A{
x=1,y=2
};
enum class B:unsigned long {
x=0x80000000,y=0x40000000
};
template<>
struct enable_bitmask_operators<A>{
static const bool enable=true;
};
template<>
struct enable_bitmask_operators<B>{
static const bool enable=true;
};
enum class C{x,y};
int main(){
A a1=A::x | A::y;
A a2=a1&A::y;
a2^=A::x;
A a3=~a1;
B b1=B::x | B::y;
B b2=b1&B::y;
b2^=B::x;
B b3=~b1;
// C c1=C::x | C::y;
// C c2=c1&C::y;
// c2^=C::x;
// C c3=~c1;
}
Here is how I would do it, hope you will find it useful.
The main problem is how to distinguish between enum flags and all other types. I would use an extra template type, eg flag_type
, which would have a member value
only for our enum flags:
template<typename T>
typename flag_type<T>::value operator | (T, T)
{
/* implementation */
}
Default flag_type
is empty
template<typename T>
struct flag_type {};
whereas for enum flags it will contain an EnumFlag
type which is returned from operator|
. Here is a macro which does it:
#define DECLARE_FLAG_TYPE(__type) \
template<> \
struct flag_type<__type> { using value = EnumFlag<__type>; }
Then, we can use it to define enum flags in both outer scope and in classes:
enum class Option
{
One = 1 << 0,
Two = 1 << 1,
Three = 1 << 2
};
DECLARE_FLAG_TYPE(Option);
class Class
{
public:
enum class Option
{
Four = 1 << 0,
Five = 1 << 1
};
};
DECLARE_FLAG_TYPE(Class::Option);
This solution doesn't require any additional macros\\using to enum class declaration at all:
enum class MyEnum { Value1 = 1 << 0, Value2 = 1 << 1 };
using MyEnums = flags<MyEnum>; // actually this line is not necessary
auto mask = Value1 | Value2; // set flags Value1 and Value 2
if (mask & Value2) { // if Value2 flag is set
doSomething();
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.