Define enum element value using an operation on another enum values - c++

Here is what I need to do: define, inside a class, two enumerations, the second having elements defined using elements values from the first.
So something like this:
class MyClass
{
public:
enum class Elem {
A=1, B=2, C=4, D=8
};
enum class Group {
first = Elem::A | Elem::B,
second = Elem::A | Elem::C,
//...
}; <-- compilation error
};
However, this does not compile due to the fact that | is not defined by default for enum classes.
I tried to define the | operator for Elem enum, outside of the MyClass class (after the class body), but the operator is then not known at the time the Group enum is defined.
So I then tried the following, i.e. defining a constexpr function inside the class:
class MyClass
{
public:
enum class Elem {
A=1, B=2, C=4, D=8
};
constexpr static unsigned int merge(
std::initializer_list<MyClass::Elem> list)
{
//Test only: should be an '|' on all list elements
return 1;
}
enum class Group {
first = merge({Elem::A,Elem::B}),
second = merge({Elem::A,Elem::C}),
/*...*/
};
};
But I get the following error:
error: static constexpr unsigned int
merge(std::initializer_list list) called in a constant
expression
I understood from here and there that the merge method is considered declared and usable only after the class has been fully declared.
The last solution I can think of is using macros like this:
#define MERGE2ELEMS( a, b ) static_cast<unsigned int>(a) | static_cast<unsigned int>(b)
#define MERGE3ELEMS( a, b, c ) static_cast<unsigned int>(a) | MERGE2ELEMS( b, c )
#define MERGE4ELEMS( a, b, c, d ) static_cast<unsigned int>(a) | MERGE3ELEMS( b, c, d )
#define MERGE5ELEMS( a, b, c, d, e ) static_cast<unsigned int>(a) | MERGE4ELEMS( b, c, d, e )
...
But I need to be able to merge up to 20 Elems and writing 20 macros like this does not seem to be a suitable solution.
What would be the way to go here?

You may play with the order of definition:
class MyClass {
public:
enum class Elem { A = 1, B = 2, C = 4, D = 8 };
enum class Group;
};
constexpr MyClass::Elem operator|(
const MyClass::Elem& l, const MyClass::Elem& r) {
return static_cast<MyClass::Elem>(
static_cast<int>(l) | static_cast<int>(r)
);
}
enum class MyClass::Group {
first = Elem::A | Elem::B,
second = Elem::A | Elem::C,
};
Live demo
But the entire idea sorta goes against the concept of type-safe enum. Maybe you could just use the good old unsafe ones?

What about casting the values of Elem enum?
first = int(Elem::A) | int(Elem::B),
second = int(Elem::A) | int(Elem::C),

You need a static cast to the integral type corresponding to enumerator so there will be built-in operator |:
class MyClass
{
public: enum class Elem: unsigned int
{
A=1, B=2, C=4, D=8
};
public: enum class Group: unsigned int
{
first = static_cast<unsigned int>(Elem::A) | static_cast<unsigned int>(Elem::B)
, second = static_cast<unsigned int>(Elem::A) | static_cast<unsigned int>(Elem::C)
};
};

Related

C++ enum variable setting to more than one value [duplicate]

I have a problem putting method args to my class:
class A {
public:
enum Mode {ModeA, ModeB, ModeC};
... // other methods, constructor etc
void setMode(Mode m) {
mMode = m;
}
private:
Mode mMode;
}
int main(int argc, char **argv) {
A a;
a.setMode(A::ModeA | A::ModeC );
return 0;
}
The problem, I get a C++ compiler error invalid vconversion from int to A::Mode,
I dont understand, why I can't concat to enum values? I need to concat values in my
code, so any help to solve this would be very nice.
The result of operator| for two enums is not an enum by default. After your class, add something like this:
A::Mode operator|( A::Mode a, A::Mode b )
{
return A::Mode( int( a ) | int( b ) );
}
if your standard library supports it, the following is more future proof as the conversion to int is not always correct:
A::Mode operator|( A::Mode a, A::Mode b )
{
typedef std::underlying_type< A::Mode >::type UL;
return A::Mode( static_cast< UL >( a ) | static_cast< UL >( b ) );
}
Unlike the other answer, you just add this once (to the right place) and all uses are automatically covered.
May be you need this :
a.setMode( (A::Mode) (A::ModeA | A::ModeC ));
A::ModeA | A::ModeC makes an int so cast it to A::Mode again
Underlying type of your enum is in this case probably int and your compiler can not rely on the flag constructed using the | (bitwise or) being a valid value from this enum.
However, you know that the result will be a valid value from this enum, so you could do:
A::Mode newMode = (A::Mode) (A::ModeA | A::ModeC);
a.setMode(newMode);

Check same enum, C++

I am abstracting my problem now but I am in this kind of situation.
Let's say I have 2 enums that are in the same namespace.
namespace some_namespace {
enum class Something{
S,
O,
M,
E,
T,
H,
I,
N,
G
};
enum class Else{
E,
L,
S
};
}
Now let's create 2 structs which have as a static field some value of these enums.
struct SomeStruct{
static constexpr int enumValue = static_cast<int>(some_namespace::Something::T);
};
struct AnotherStruct {
static constexpr int enumValue = static_cast<int>(some_namespace::Something::O);
};
How can I check whether the enumValues of this 2 structs are from the same enum class or not? I think I shall give some values to my enum fields and use some bitwise operator on enum values to distinguish? Can someone help? thanks)
Using just the static_casted enumValue it is not possible to distinguish the originating enum(as pointed out by #Sam). What you can instead do is introduce a new field that stores the underlying enum class type and leverage that to make the distinction.
enum class E1{ One, Two };
enum class E2{Three, Four };
struct SomeStruct{
static constexpr int enumValue = static_cast<int>(E1::One);
using UnderlyingT = E1;
};
struct AnotherStruct {
static constexpr int enumValue = static_cast<int>(E2::Three);
using UnderlyingT = E2;
};
static_assert(!std::is_same_v<SomeStruct::UnderlyingT, AnotherStruct::UnderlyingT>);
Code Link
As already indicated in the comments, you don't want to convert your enum to an int if you still want to know the type.
There might be some reasons to keep the type and the scoping while wanting to implicit conversion to the underlying type.
What you could do is to wrap the enum into a class that converts to both the underlying type AND the actual enum.
#include <type_traits>
template<typename TEnum>
class ImplicitEnumConverter final
{
public:
TEnum e;
using TUnderlyingType = std::underlying_type_t<TEnum>;
constexpr ImplicitEnumConverter(TEnum e) : e{e} {}
constexpr operator TUnderlyingType() const noexcept
{
return static_cast<TUnderlyingType>(e);
}
constexpr operator TEnum() const noexcept
{
return e;
}
};
struct SomeStruct{
static constexpr auto enumValue = ImplicitEnumConverter{some_namespace::Something::T};
};
Code at compiler-explorer
This way, you are able to keep all the type-safe information where this is relevant AND you are able to convert it implicitly to an int.
The answer was simpler than I thought.
So I declare enum like this.
namespace some_namespace {
enum class Something{
S = 0,
O = 2,
M = 4,
E = 6,
T = 8,
H = 10,
I = 12,
N = 14,
G = 16
};
enum class Else{
E = 1,
L = 3,
S = 5
};
}
And then this leads me to check whether two integer values have the same parity or not . Thus
if((SomeStruct::enum_value + AnotherStruct::enum_value) % 2 == 0) {
// Same enum
} else {
// not same enum.
}

Translating from Java: How to define lambda members for enum types in C++?

In Java, it is possible to do the following for e.g. defining different variants of a simple calculation (in this case, inverted document frequency weights from the total number of documents D and the numbe rof documents that contain a term d):
package an.nlp.library.weights;
import java.util.function.BiFunction;
public enum IDF implements BiFunction<Long,Long,Double> {
UNARY( ( D, d ) -> 1d ),
IDF( ( D, d ) -> Math.log( D / d ) ),
IDFS( ( D, d ) -> Math.log1p( D / d ) ),
PIDF( ( D, d ) -> Math.log( D - d / d ) ),
;
private BiFunction<Long,Long,Double> func;
private IDF( BiFunction<Long,Long,Double> func ) {
this.func = func;
}
public Double weight( long D, long d ) {
return func.apply( D, d );
}
#Override
public Double apply( Long t, Long u ) {
return func.apply( t, u );
}
}
This can then be called from client code via, e.g.:
getIdf( long D, long d, IDF mode ) {
return mode.apply( D, d );
}
etc.
How would one accomplish the same in C++? i.e something like, calling something like:
// Obviously wrong, as I have no idea how to do it, hence the qeustion:
std::vector<double> getIdfWeights( long D, std::vector<double> ds, IDF mode ) {
return std::transform( ds.begin(), ds.end(), ds.begin(), IDF );
}
In other words, what would be the correct syntax to use to add 1) members to an enum type in C++ and 2) have those member values be lambdas that could then be called from somewhere else? From what I've been reading, apparently this is what enum classes are for, but I'm a C++ n00b so I don't entirelly understand how those work.
Enums in C++ are only integer values. They can't have members. enum class just removes integer conversions from the enum values.
You can do something similar with a class, e.g.
class Foo
{
int(*)(int) func;
int value;
public:
operator int() {
return value;
};
int operator()(int i) {
return func(i);
}
static constexpr Foo Value_A = { frob, 0 };
static constexpr Foo Value_B = { mung, 1 };
};

Combining enum values in C++ [duplicate]

Treating enums as flags works nicely in C# via the [Flags] attribute, but what's the best way to do this in C++?
For example, I'd like to write:
enum AnimalFlags
{
HasClaws = 1,
CanFly =2,
EatsFish = 4,
Endangered = 8
};
seahawk.flags = CanFly | EatsFish | Endangered;
However, I get compiler errors regarding int/enum conversions. Is there a nicer way to express this than just blunt casting? Preferably, I don't want to rely on constructs from 3rd party libraries such as boost or Qt.
EDIT: As indicated in the answers, I can avoid the compiler error by declaring seahawk.flags as int. However, I'd like to have some mechanism to enforce type safety, so someone can't write seahawk.flags = HasMaximizeButton.
The "correct" way is to define bit operators for the enum, as:
enum AnimalFlags
{
HasClaws = 1,
CanFly = 2,
EatsFish = 4,
Endangered = 8
};
inline AnimalFlags operator|(AnimalFlags a, AnimalFlags b)
{
return static_cast<AnimalFlags>(static_cast<int>(a) | static_cast<int>(b));
}
Etc. rest of the bit operators. Modify as needed if the enum range exceeds int range.
Note (also a bit off topic): Another way to make unique flags can be done using a bit shift. I, myself, find this easier to read.
enum Flags
{
A = 1 << 0, // binary 0001
B = 1 << 1, // binary 0010
C = 1 << 2, // binary 0100
D = 1 << 3 // binary 1000
};
It can hold values up to an int so that is, most of the time, 32 flags which is clearly reflected in the shift amount.
Note if you are working in Windows environment, there is a DEFINE_ENUM_FLAG_OPERATORS macro defined in winnt.h that does the job for you. So in this case, you can do this:
enum AnimalFlags
{
HasClaws = 1,
CanFly =2,
EatsFish = 4,
Endangered = 8
};
DEFINE_ENUM_FLAG_OPERATORS(AnimalFlags)
seahawk.flags = CanFly | EatsFish | Endangered;
For lazy people like me, here is templated solution to copy&paste:
template<class T> inline T operator~ (T a) { return (T)~(int)a; }
template<class T> inline T operator| (T a, T b) { return (T)((int)a | (int)b); }
template<class T> inline T operator& (T a, T b) { return (T)((int)a & (int)b); }
template<class T> inline T operator^ (T a, T b) { return (T)((int)a ^ (int)b); }
template<class T> inline T& operator|= (T& a, T b) { return (T&)((int&)a |= (int)b); }
template<class T> inline T& operator&= (T& a, T b) { return (T&)((int&)a &= (int)b); }
template<class T> inline T& operator^= (T& a, T b) { return (T&)((int&)a ^= (int)b); }
What type is the seahawk.flags variable?
In standard C++, enumerations are not type-safe. They are effectively integers.
AnimalFlags should NOT be the type of your variable. Your variable should be int and the error will go away.
Putting hexadecimal values like some other people suggested is not needed. It makes no difference.
The enum values ARE of type int by default. So you can surely bitwise OR combine them and put them together and store the result in an int.
The enum type is a restricted subset of int whose value is one of its enumerated values. Hence, when you make some new value outside of that range, you can't assign it without casting to a variable of your enum type.
You can also change the enum value types if you'd like, but there is no point for this question.
EDIT: The poster said they were concerned with type safety and they don't want a value that should not exist inside the int type.
But it would be type unsafe to put a value outside of AnimalFlags's range inside a variable of type AnimalFlags.
There is a safe way to check for out of range values though inside the int type...
int iFlags = HasClaws | CanFly;
//InvalidAnimalFlagMaxValue-1 gives you a value of all the bits
// smaller than itself set to 1
//This check makes sure that no other bits are set.
assert(iFlags & ~(InvalidAnimalFlagMaxValue-1) == 0);
enum AnimalFlags {
HasClaws = 1,
CanFly =2,
EatsFish = 4,
Endangered = 8,
// put new enum values above here
InvalidAnimalFlagMaxValue = 16
};
The above doesn't stop you from putting an invalid flag from a different enum that has the value 1,2,4, or 8 though.
If you want absolute type safety then you could simply create a std::set and store each flag inside there. It is not space efficient, but it is type safe and gives you the same ability as a bitflag int does.
C++0x note: Strongly typed enums
In C++0x you can finally have type safe enum values....
enum class AnimalFlags {
CanFly = 2,
HasClaws = 4
};
if(CanFly == 2) { }//Compiling error
I find the currently accepted answer by eidolon too dangerous. The compiler's optimizer might make assumptions about possible values in the enum and you might get garbage back with invalid values. And usually nobody wants to define all possible permutations in flags enums.
As Brian R. Bondy states below, if you're using C++11 (which everyone should, it's that good) you can now do this more easily with enum class:
enum class ObjectType : uint32_t
{
ANIMAL = (1 << 0),
VEGETABLE = (1 << 1),
MINERAL = (1 << 2)
};
constexpr enum ObjectType operator |( const enum ObjectType selfValue, const enum ObjectType inValue )
{
return (enum ObjectType)(uint32_t(selfValue) | uint32_t(inValue));
}
// ... add more operators here.
This ensures a stable size and value range by specifying a type for the enum, inhibits automatic downcasting of enums to ints etc. by using enum class, and uses constexpr to ensure the code for the operators gets inlined and thus just as fast as regular numbers.
For people stuck with pre-11 C++ dialects
If I was stuck with a compiler that doesn't support C++11, I'd go with wrapping an int-type in a class that then permits only use of bitwise operators and the types from that enum to set its values:
template<class ENUM,class UNDERLYING=typename std::underlying_type<ENUM>::type>
class SafeEnum
{
public:
SafeEnum() : mFlags(0) {}
SafeEnum( ENUM singleFlag ) : mFlags(singleFlag) {}
SafeEnum( const SafeEnum& original ) : mFlags(original.mFlags) {}
SafeEnum& operator |=( ENUM addValue ) { mFlags |= addValue; return *this; }
SafeEnum operator |( ENUM addValue ) { SafeEnum result(*this); result |= addValue; return result; }
SafeEnum& operator &=( ENUM maskValue ) { mFlags &= maskValue; return *this; }
SafeEnum operator &( ENUM maskValue ) { SafeEnum result(*this); result &= maskValue; return result; }
SafeEnum operator ~() { SafeEnum result(*this); result.mFlags = ~result.mFlags; return result; }
explicit operator bool() { return mFlags != 0; }
protected:
UNDERLYING mFlags;
};
You can define this pretty much like a regular enum + typedef:
enum TFlags_
{
EFlagsNone = 0,
EFlagOne = (1 << 0),
EFlagTwo = (1 << 1),
EFlagThree = (1 << 2),
EFlagFour = (1 << 3)
};
typedef SafeEnum<enum TFlags_> TFlags;
And usage is similar as well:
TFlags myFlags;
myFlags |= EFlagTwo;
myFlags |= EFlagThree;
if( myFlags & EFlagTwo )
std::cout << "flag 2 is set" << std::endl;
if( (myFlags & EFlagFour) == EFlagsNone )
std::cout << "flag 4 is not set" << std::endl;
And you can also override the underlying type for binary-stable enums (like C++11's enum foo : type) using the second template parameter, i.e. typedef SafeEnum<enum TFlags_,uint8_t> TFlags;.
I marked the operator bool override with C++11's explicit keyword to prevent it from resulting in int conversions, as those could cause sets of flags to end up collapsed into 0 or 1 when writing them out. If you can't use C++11, leave that overload out and rewrite the first conditional in the example usage as (myFlags & EFlagTwo) == EFlagTwo.
Easiest way to do this as shown here, using the standard library class bitset.
To emulate the C# feature in a type-safe way, you'd have to write a template wrapper around the bitset, replacing the int arguments with an enum given as a type parameter to the template. Something like:
template <class T, int N>
class FlagSet
{
bitset<N> bits;
FlagSet(T enumVal)
{
bits.set(enumVal);
}
// etc.
};
enum MyFlags
{
FLAG_ONE,
FLAG_TWO
};
FlagSet<MyFlags, 2> myFlag;
In my opinion none of the answers so far are ideal. To be ideal I would expect the solution:
Support the ==,!=,=,&,&=,|,|= and ~ operators in the conventional
sense (i.e. a & b)
Be type safe i.e. not permit non-enumerated values such as literals or integer types to be assigned (except for bitwise combinations of enumerated values) or allow an enum variable to be assigned to an integer type
Permit expressions such as if (a & b)...
Not require evil macros, implementation specific features or other hacks
Most of the solutions thus far fall over on points 2 or 3. WebDancer's is the closes in my opinion but fails at point 3 and needs to be repeated for every enum.
My proposed solution is a generalized version of WebDancer's that also addresses point 3:
#include <cstdint>
#include <type_traits>
template<typename T, typename = typename std::enable_if<std::is_enum<T>::value, T>::type>
class auto_bool
{
T val_;
public:
constexpr auto_bool(T val) : val_(val) {}
constexpr operator T() const { return val_; }
constexpr explicit operator bool() const
{
return static_cast<std::underlying_type_t<T>>(val_) != 0;
}
};
template <typename T, typename = typename std::enable_if<std::is_enum<T>::value, T>::type>
constexpr auto_bool<T> operator&(T lhs, T rhs)
{
return static_cast<T>(
static_cast<typename std::underlying_type<T>::type>(lhs) &
static_cast<typename std::underlying_type<T>::type>(rhs));
}
template <typename T, typename = typename std::enable_if<std::is_enum<T>::value, T>::type>
constexpr T operator|(T lhs, T rhs)
{
return static_cast<T>(
static_cast<typename std::underlying_type<T>::type>(lhs) |
static_cast<typename std::underlying_type<T>::type>(rhs));
}
enum class AnimalFlags : uint8_t
{
HasClaws = 1,
CanFly = 2,
EatsFish = 4,
Endangered = 8
};
enum class PlantFlags : uint8_t
{
HasLeaves = 1,
HasFlowers = 2,
HasFruit = 4,
HasThorns = 8
};
int main()
{
AnimalFlags seahawk = AnimalFlags::CanFly; // Compiles, as expected
AnimalFlags lion = AnimalFlags::HasClaws; // Compiles, as expected
PlantFlags rose = PlantFlags::HasFlowers; // Compiles, as expected
// rose = 1; // Won't compile, as expected
if (seahawk != lion) {} // Compiles, as expected
// if (seahawk == rose) {} // Won't compile, as expected
// seahawk = PlantFlags::HasThorns; // Won't compile, as expected
seahawk = seahawk | AnimalFlags::EatsFish; // Compiles, as expected
lion = AnimalFlags::HasClaws | // Compiles, as expected
AnimalFlags::Endangered;
// int eagle = AnimalFlags::CanFly | // Won't compile, as expected
// AnimalFlags::HasClaws;
// int has_claws = seahawk & AnimalFlags::CanFly; // Won't compile, as expected
if (seahawk & AnimalFlags::CanFly) {} // Compiles, as expected
seahawk = seahawk & AnimalFlags::CanFly; // Compiles, as expected
return 0;
}
This creates overloads of the necessary operators but uses SFINAE to limit them to enumerated types. Note that in the interests of brevity I haven't defined all of the operators but the only one that is any different is the &. The operators are currently global (i.e. apply to all enumerated types) but this could be reduced either by placing the overloads in a namespace (what I do), or by adding additional SFINAE conditions (perhaps using particular underlying types, or specially created type aliases). The underlying_type_t is a C++14 feature but it seems to be well supported and is easy to emulate for C++11 with a simple template<typename T> using underlying_type_t = underlying_type<T>::type;
Edit: I incorporated the change suggested by Vladimir Afinello. Tested with GCC 10, CLANG 13 and Visual Studio 2022.
Only syntactic sugar. No additional metadata.
namespace UserRole // grupy
{
constexpr uint8_t dea = 1;
constexpr uint8_t red = 2;
constexpr uint8_t stu = 4;
constexpr uint8_t kie = 8;
constexpr uint8_t adm = 16;
constexpr uint8_t mas = 32;
}
Flag operators on integral type just works.
The C++ standard explicitly talks about this, see section "17.5.2.1.3 Bitmask types":
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3485.pdf
Given this "template" you get:
enum AnimalFlags : unsigned int
{
HasClaws = 1,
CanFly = 2,
EatsFish = 4,
Endangered = 8
};
constexpr AnimalFlags operator|(AnimalFlags X, AnimalFlags Y) {
return static_cast<AnimalFlags>(
static_cast<unsigned int>(X) | static_cast<unsigned int>(Y));
}
AnimalFlags& operator|=(AnimalFlags& X, AnimalFlags Y) {
X = X | Y; return X;
}
And similar for the other operators.
Also note the "constexpr", it is needed if you want the compiler to be able to execute the operators compile time.
If you are using C++/CLI and want to able assign to enum members of ref classes you need to use tracking references instead:
AnimalFlags% operator|=(AnimalFlags% X, AnimalFlags Y) {
X = X | Y; return X;
}
NOTE: This sample is not complete, see section "17.5.2.1.3 Bitmask types" for a complete set of operators.
I use the following macro:
#define ENUM_FLAG_OPERATORS(T) \
inline T operator~ (T a) { return static_cast<T>( ~static_cast<std::underlying_type<T>::type>(a) ); } \
inline T operator| (T a, T b) { return static_cast<T>( static_cast<std::underlying_type<T>::type>(a) | static_cast<std::underlying_type<T>::type>(b) ); } \
inline T operator& (T a, T b) { return static_cast<T>( static_cast<std::underlying_type<T>::type>(a) & static_cast<std::underlying_type<T>::type>(b) ); } \
inline T operator^ (T a, T b) { return static_cast<T>( static_cast<std::underlying_type<T>::type>(a) ^ static_cast<std::underlying_type<T>::type>(b) ); } \
inline T& operator|= (T& a, T b) { return reinterpret_cast<T&>( reinterpret_cast<std::underlying_type<T>::type&>(a) |= static_cast<std::underlying_type<T>::type>(b) ); } \
inline T& operator&= (T& a, T b) { return reinterpret_cast<T&>( reinterpret_cast<std::underlying_type<T>::type&>(a) &= static_cast<std::underlying_type<T>::type>(b) ); } \
inline T& operator^= (T& a, T b) { return reinterpret_cast<T&>( reinterpret_cast<std::underlying_type<T>::type&>(a) ^= static_cast<std::underlying_type<T>::type>(b) ); }
It is similar to the ones mentioned above but has several improvements:
It is type safe (it does not suppose that the underlying type is an int)
It does not require to specify manually the underlying type (as opposed to #LunarEclipse 's answer)
It does need to include type_traits:
#include <type_traits>
I found myself asking the same question and came up with a generic C++11 based solution, similar to soru's:
template <typename TENUM>
class FlagSet {
private:
using TUNDER = typename std::underlying_type<TENUM>::type;
std::bitset<std::numeric_limits<TUNDER>::max()> m_flags;
public:
FlagSet() = default;
template <typename... ARGS>
FlagSet(TENUM f, ARGS... args) : FlagSet(args...)
{
set(f);
}
FlagSet& set(TENUM f)
{
m_flags.set(static_cast<TUNDER>(f));
return *this;
}
bool test(TENUM f)
{
return m_flags.test(static_cast<TUNDER>(f));
}
FlagSet& operator|=(TENUM f)
{
return set(f);
}
};
The interface can be improved to taste. Then it can be used like so:
FlagSet<Flags> flags{Flags::FLAG_A, Flags::FLAG_C};
flags |= Flags::FLAG_D;
If your compiler doesn't support strongly typed enums yet, you can give a look to the following article from the c++ source:
From the abstract:
This article presents a solution to the problem of constraining bit operations to
allow only safe and legitimate ones, and turn all invalid bit manipulations into
compile-time errors. Best of all, the syntax of bit operations remains unchanged,
and the code working with bits does not need to be modified, except possibly to
fix errors that had as yet remained undetected.
Here's an option for bitmasks if you don't actually have a use for the individual enum values (ex. you don't need to switch off of them)... and if you aren't worried about maintaining binary compatibility ie: you don't care where your bits live... which you probably are. Also you'd better not be too concerned with scoping and access control. Hmmm, enums have some nice properties for bit-fields... wonder if anyone has ever tried that :)
struct AnimalProperties
{
bool HasClaws : 1;
bool CanFly : 1;
bool EatsFish : 1;
bool Endangered : 1;
};
union AnimalDescription
{
AnimalProperties Properties;
int Flags;
};
void TestUnionFlags()
{
AnimalDescription propertiesA;
propertiesA.Properties.CanFly = true;
AnimalDescription propertiesB = propertiesA;
propertiesB.Properties.EatsFish = true;
if( propertiesA.Flags == propertiesB.Flags )
{
cout << "Life is terrible :(";
}
else
{
cout << "Life is great!";
}
AnimalDescription propertiesC = propertiesA;
if( propertiesA.Flags == propertiesC.Flags )
{
cout << "Life is great!";
}
else
{
cout << "Life is terrible :(";
}
}
We can see that life is great, we have our discrete values, and we have a nice int to & and | to our hearts content, which still has context of what its bits mean. Everything is consistent and predictable... for me... as long as I keep using Microsoft's VC++ compiler w/ Update 3 on Win10 x64 and don't touch my compiler flags :)
Even though everything is great... we have some context as to the meaning of flags now, since its in a union w/ the bitfield in the terrible real world where your program may be be responsible for more than a single discrete task you could still accidentally (quite easily) smash two flags fields of different unions together (say, AnimalProperties and ObjectProperties, since they're both ints), mixing up all yours bits, which is a horrible bug to trace down... and how I know many people on this post don't work with bitmasks very often, since building them is easy and maintaining them is hard.
class AnimalDefinition {
public:
static AnimalDefinition *GetAnimalDefinition( AnimalFlags flags ); //A little too obvious for my taste... NEXT!
static AnimalDefinition *GetAnimalDefinition( AnimalProperties properties ); //Oh I see how to use this! BORING, NEXT!
static AnimalDefinition *GetAnimalDefinition( int flags ); //hmm, wish I could see how to construct a valid "flags" int without CrossFingers+Ctrl+Shift+F("Animal*"). Maybe just hard-code 16 or something?
AnimalFlags animalFlags; //Well this is *way* too hard to break unintentionally, screw this!
int flags; //PERFECT! Nothing will ever go wrong here...
//wait, what values are used for this particular flags field? Is this AnimalFlags or ObjectFlags? Or is it RuntimePlatformFlags? Does it matter? Where's the documentation?
//Well luckily anyone in the code base and get confused and destroy the whole program! At least I don't need to static_cast anymore, phew!
private:
AnimalDescription m_description; //Oh I know what this is. All of the mystery and excitement of life has been stolen away :(
}
So then you make your union declaration private to prevent direct access to "Flags", and have to add getters/setters and operator overloads, then make a macro for all that, and you're basically right back where you started when you tried to do this with an Enum.
Unfortunately if you want your code to be portable, I don't think there is any way to either A) guarantee the bit layout or B) determine the bit layout at compile time (so you can track it and at least correct for changes across versions/platforms etc)
Offset in a struct with bit fields
At runtime you can play tricks w/ setting the the fields and XORing the flags to see which bits did change, sounds pretty crappy to me though verses having a 100% consistent, platform independent, and completely deterministic solution ie: an ENUM.
TL;DR:
Don't listen to the haters. C++ is not English. Just because the literal definition of an abbreviated keyword inherited from C might not fit your usage doesn't mean you shouldn't use it when the C and C++ definition of the keyword absolutely includes your use case. You can also use structs to model things other than structures, and classes for things other than school and social caste. You may use float for values which are grounded. You may use char for variables which are neither un-burnt nor a person in a novel, play, or movie. Any programmer who goes to the dictionary to determine the meaning of a keyword before the language spec is a... well I'll hold my tongue there.
If you do want your code modeled after spoken language you'd be best off writing in Objective-C, which incidentally also uses enums heavily for bitfields.
I'd like to elaborate on Uliwitness answer, fixing his code for C++98 and using the Safe Bool idiom, for lack of the std::underlying_type<> template and the explicit keyword in C++ versions below C++11.
I also modified it so that the enum values can be sequential without any explicit assignment, so you can have
enum AnimalFlags_
{
HasClaws,
CanFly,
EatsFish,
Endangered
};
typedef FlagsEnum<AnimalFlags_> AnimalFlags;
seahawk.flags = AnimalFlags() | CanFly | EatsFish | Endangered;
You can then get the raw flags value with
seahawk.flags.value();
Here's the code.
template <typename EnumType, typename Underlying = int>
class FlagsEnum
{
typedef Underlying FlagsEnum::* RestrictedBool;
public:
FlagsEnum() : m_flags(Underlying()) {}
FlagsEnum(EnumType singleFlag):
m_flags(1 << singleFlag)
{}
FlagsEnum(const FlagsEnum& original):
m_flags(original.m_flags)
{}
FlagsEnum& operator |=(const FlagsEnum& f) {
m_flags |= f.m_flags;
return *this;
}
FlagsEnum& operator &=(const FlagsEnum& f) {
m_flags &= f.m_flags;
return *this;
}
friend FlagsEnum operator |(const FlagsEnum& f1, const FlagsEnum& f2) {
return FlagsEnum(f1) |= f2;
}
friend FlagsEnum operator &(const FlagsEnum& f1, const FlagsEnum& f2) {
return FlagsEnum(f1) &= f2;
}
FlagsEnum operator ~() const {
FlagsEnum result(*this);
result.m_flags = ~result.m_flags;
return result;
}
operator RestrictedBool() const {
return m_flags ? &FlagsEnum::m_flags : 0;
}
Underlying value() const {
return m_flags;
}
protected:
Underlying m_flags;
};
Currently there is no language support for enum flags, Meta classes might inherently add this feature if it would ever be part of the c++ standard.
My solution would be to create enum-only instantiated template functions adding support for type-safe bitwise operations for enum class using its underlying type:
File: EnumClassBitwise.h
#pragma once
#ifndef _ENUM_CLASS_BITWISE_H_
#define _ENUM_CLASS_BITWISE_H_
#include <type_traits>
//unary ~operator
template <typename Enum, typename std::enable_if_t<std::is_enum<Enum>::value, int> = 0>
constexpr inline Enum& operator~ (Enum& val)
{
val = static_cast<Enum>(~static_cast<std::underlying_type_t<Enum>>(val));
return val;
}
// & operator
template <typename Enum, typename std::enable_if_t<std::is_enum<Enum>::value, int> = 0>
constexpr inline Enum operator& (Enum lhs, Enum rhs)
{
return static_cast<Enum>(static_cast<std::underlying_type_t<Enum>>(lhs) & static_cast<std::underlying_type_t<Enum>>(rhs));
}
// &= operator
template <typename Enum, typename std::enable_if_t<std::is_enum<Enum>::value, int> = 0>
constexpr inline Enum operator&= (Enum& lhs, Enum rhs)
{
lhs = static_cast<Enum>(static_cast<std::underlying_type_t<Enum>>(lhs) & static_cast<std::underlying_type_t<Enum>>(rhs));
return lhs;
}
//| operator
template <typename Enum, typename std::enable_if_t<std::is_enum<Enum>::value, int> = 0>
constexpr inline Enum operator| (Enum lhs, Enum rhs)
{
return static_cast<Enum>(static_cast<std::underlying_type_t<Enum>>(lhs) | static_cast<std::underlying_type_t<Enum>>(rhs));
}
//|= operator
template <typename Enum, typename std::enable_if_t<std::is_enum<Enum>::value, int> = 0>
constexpr inline Enum& operator|= (Enum& lhs, Enum rhs)
{
lhs = static_cast<Enum>(static_cast<std::underlying_type_t<Enum>>(lhs) | static_cast<std::underlying_type_t<Enum>>(rhs));
return lhs;
}
#endif // _ENUM_CLASS_BITWISE_H_
For convenience and for reducing mistakes, you might want to wrap your bit flags operations for enums and for integers as well:
File: BitFlags.h
#pragma once
#ifndef _BIT_FLAGS_H_
#define _BIT_FLAGS_H_
#include "EnumClassBitwise.h"
template<typename T>
class BitFlags
{
public:
constexpr inline BitFlags() = default;
constexpr inline BitFlags(T value) { mValue = value; }
constexpr inline BitFlags operator| (T rhs) const { return mValue | rhs; }
constexpr inline BitFlags operator& (T rhs) const { return mValue & rhs; }
constexpr inline BitFlags operator~ () const { return ~mValue; }
constexpr inline operator T() const { return mValue; }
constexpr inline BitFlags& operator|=(T rhs) { mValue |= rhs; return *this; }
constexpr inline BitFlags& operator&=(T rhs) { mValue &= rhs; return *this; }
constexpr inline bool test(T rhs) const { return (mValue & rhs) == rhs; }
constexpr inline void set(T rhs) { mValue |= rhs; }
constexpr inline void clear(T rhs) { mValue &= ~rhs; }
private:
T mValue;
};
#endif //#define _BIT_FLAGS_H_
Possible usage:
#include <cstdint>
#include <BitFlags.h>
void main()
{
enum class Options : uint32_t
{
NoOption = 0 << 0
, Option1 = 1 << 0
, Option2 = 1 << 1
, Option3 = 1 << 2
, Option4 = 1 << 3
};
const uint32_t Option1 = 1 << 0;
const uint32_t Option2 = 1 << 1;
const uint32_t Option3 = 1 << 2;
const uint32_t Option4 = 1 << 3;
//Enum BitFlags
BitFlags<Options> optionsEnum(Options::NoOption);
optionsEnum.set(Options::Option1 | Options::Option3);
//Standard integer BitFlags
BitFlags<uint32_t> optionsUint32(0);
optionsUint32.set(Option1 | Option3);
return 0;
}
#Xaqq has provided a really nice type-safe way to use enum flags here by a flag_set class.
I published the code in GitHub, usage is as follows:
#include "flag_set.hpp"
enum class AnimalFlags : uint8_t {
HAS_CLAWS,
CAN_FLY,
EATS_FISH,
ENDANGERED,
_
};
int main()
{
flag_set<AnimalFlags> seahawkFlags(AnimalFlags::HAS_CLAWS
| AnimalFlags::EATS_FISH
| AnimalFlags::ENDANGERED);
if (seahawkFlags & AnimalFlags::ENDANGERED)
cout << "Seahawk is endangered";
}
Another macro solution, but unlike the existing answers this does not use reinterpret_cast (or a C-cast) to cast between Enum& and Int&, which is forbidden in standard C++ (see this post).
#define MAKE_FLAGS_ENUM(TEnum, TUnder) \
TEnum operator~ ( TEnum a ) { return static_cast<TEnum> (~static_cast<TUnder> (a) ); } \
TEnum operator| ( TEnum a, TEnum b ) { return static_cast<TEnum> ( static_cast<TUnder> (a) | static_cast<TUnder>(b) ); } \
TEnum operator& ( TEnum a, TEnum b ) { return static_cast<TEnum> ( static_cast<TUnder> (a) & static_cast<TUnder>(b) ); } \
TEnum operator^ ( TEnum a, TEnum b ) { return static_cast<TEnum> ( static_cast<TUnder> (a) ^ static_cast<TUnder>(b) ); } \
TEnum& operator|= ( TEnum& a, TEnum b ) { a = static_cast<TEnum>(static_cast<TUnder>(a) | static_cast<TUnder>(b) ); return a; } \
TEnum& operator&= ( TEnum& a, TEnum b ) { a = static_cast<TEnum>(static_cast<TUnder>(a) & static_cast<TUnder>(b) ); return a; } \
TEnum& operator^= ( TEnum& a, TEnum b ) { a = static_cast<TEnum>(static_cast<TUnder>(a) ^ static_cast<TUnder>(b) ); return a; }
Losing the reinterpret_cast means we can't rely on the x |= y syntax any more, but by expanding these into their x = x | y forms we no longer need it.
Note: You can use std::underlying_type to obtain TUnder, I've not included it for brevity.
You are confusing objects and collections of objects. Specifically, you are confusing binary flags with sets of binary flags. A proper solution would look like this:
// These are individual flags
enum AnimalFlag // Flag, not Flags
{
HasClaws = 0,
CanFly,
EatsFish,
Endangered
};
class AnimalFlagSet
{
int m_Flags;
public:
AnimalFlagSet() : m_Flags(0) { }
void Set( AnimalFlag flag ) { m_Flags |= (1 << flag); }
void Clear( AnimalFlag flag ) { m_Flags &= ~ (1 << flag); }
bool Get( AnimalFlag flag ) const { return (m_Flags >> flag) & 1; }
};
Here is my solution without needing any bunch of overloading or casting:
namespace EFoobar
{
enum
{
FB_A = 0x1,
FB_B = 0x2,
FB_C = 0x4,
};
typedef long Flags;
}
void Foobar(EFoobar::Flags flags)
{
if (flags & EFoobar::FB_A)
// do sth
;
if (flags & EFoobar::FB_B)
// do sth
;
}
void ExampleUsage()
{
Foobar(EFoobar::FB_A | EFoobar::FB_B);
EFoobar::Flags otherflags = 0;
otherflags|= EFoobar::FB_B;
otherflags&= ~EFoobar::FB_B;
Foobar(otherflags);
}
I think it's ok, because we identify (non strongly typed) enums and ints anyway.
Just as a (longer) side note, if you
want to use strongly typed enums and
don't need heavy bit fiddling with your flags
performance is not an issue
I would come up with this:
#include <set>
enum class EFoobarFlags
{
FB_A = 1,
FB_B,
FB_C,
};
void Foobar(const std::set<EFoobarFlags>& flags)
{
if (flags.find(EFoobarFlags::FB_A) != flags.end())
// do sth
;
if (flags.find(EFoobarFlags::FB_B) != flags.end())
// do sth
;
}
void ExampleUsage()
{
Foobar({EFoobarFlags::FB_A, EFoobarFlags::FB_B});
std::set<EFoobarFlags> otherflags{};
otherflags.insert(EFoobarFlags::FB_B);
otherflags.erase(EFoobarFlags::FB_B);
Foobar(otherflags);
}
using C++11 initializer lists and enum class.
Copy-pasteable "evil" macro based on some of the other answers in this thread:
#include <type_traits>
/*
* Macro to allow enum values to be combined and evaluated as flags.
* * Based on:
* - DEFINE_ENUM_FLAG_OPERATORS from <winnt.h>
* - https://stackoverflow.com/a/63031334/1624459
*/
#define MAKE_ENUM_FLAGS(TEnum) \
inline TEnum operator~(TEnum a) { \
using TUnder = typename std::underlying_type_t<TEnum>; \
return static_cast<TEnum>(~static_cast<TUnder>(a)); \
} \
inline TEnum operator|(TEnum a, TEnum b) { \
using TUnder = typename std::underlying_type_t<TEnum>; \
return static_cast<TEnum>(static_cast<TUnder>(a) | static_cast<TUnder>(b)); \
} \
inline TEnum operator&(TEnum a, TEnum b) { \
using TUnder = typename std::underlying_type_t<TEnum>; \
return static_cast<TEnum>(static_cast<TUnder>(a) & static_cast<TUnder>(b)); \
} \
inline TEnum operator^(TEnum a, TEnum b) { \
using TUnder = typename std::underlying_type_t<TEnum>; \
return static_cast<TEnum>(static_cast<TUnder>(a) ^ static_cast<TUnder>(b)); \
} \
inline TEnum& operator|=(TEnum& a, TEnum b) { \
using TUnder = typename std::underlying_type_t<TEnum>; \
a = static_cast<TEnum>(static_cast<TUnder>(a) | static_cast<TUnder>(b)); \
return a; \
} \
inline TEnum& operator&=(TEnum& a, TEnum b) { \
using TUnder = typename std::underlying_type_t<TEnum>; \
a = static_cast<TEnum>(static_cast<TUnder>(a) & static_cast<TUnder>(b)); \
return a; \
} \
inline TEnum& operator^=(TEnum& a, TEnum b) { \
using TUnder = typename std::underlying_type_t<TEnum>; \
a = static_cast<TEnum>(static_cast<TUnder>(a) ^ static_cast<TUnder>(b)); \
return a; \
}
Usage
enum class Passability : std::uint8_t {
Clear = 0,
GroundUnit = 1 << 1,
FlyingUnit = 1 << 2,
Building = 1 << 3,
Tree = 1 << 4,
Mountain = 1 << 5,
Blocked = 1 << 6,
Water = 1 << 7,
Coastline = 1 << 8
};
MAKE_ENUM_FLAGS(Passability)
Advantages
Only applies to chosen enums when used explicitly.
No use of illegal reinterpret_cast.
No need to specify the underlying type.
Notes
Replace std::underlying_type_t<TEnum> with std::underlying_type<TEnum>::type if using C++ <14.
Here's a lazy C++11 solution that doesn't change the default behavior of enums. It also works for enum struct and enum class, and is constexpr.
#include <type_traits>
template<class T = void> struct enum_traits {};
template<> struct enum_traits<void> {
struct _allow_bitops {
static constexpr bool allow_bitops = true;
};
using allow_bitops = _allow_bitops;
template<class T, class R = T>
using t = typename std::enable_if<std::is_enum<T>::value and
enum_traits<T>::allow_bitops, R>::type;
template<class T>
using u = typename std::underlying_type<T>::type;
};
template<class T>
constexpr enum_traits<>::t<T> operator~(T a) {
return static_cast<T>(~static_cast<enum_traits<>::u<T>>(a));
}
template<class T>
constexpr enum_traits<>::t<T> operator|(T a, T b) {
return static_cast<T>(
static_cast<enum_traits<>::u<T>>(a) |
static_cast<enum_traits<>::u<T>>(b));
}
template<class T>
constexpr enum_traits<>::t<T> operator&(T a, T b) {
return static_cast<T>(
static_cast<enum_traits<>::u<T>>(a) &
static_cast<enum_traits<>::u<T>>(b));
}
template<class T>
constexpr enum_traits<>::t<T> operator^(T a, T b) {
return static_cast<T>(
static_cast<enum_traits<>::u<T>>(a) ^
static_cast<enum_traits<>::u<T>>(b));
}
template<class T>
constexpr enum_traits<>::t<T, T&> operator|=(T& a, T b) {
a = a | b;
return a;
}
template<class T>
constexpr enum_traits<>::t<T, T&> operator&=(T& a, T b) {
a = a & b;
return a;
}
template<class T>
constexpr enum_traits<>::t<T, T&> operator^=(T& a, T b) {
a = a ^ b;
return a;
}
To enable bitwise operators for an enum:
enum class my_enum {
Flag1 = 1 << 0,
Flag2 = 1 << 1,
Flag3 = 1 << 2,
// ...
};
// The magic happens here
template<> struct enum_traits<my_enum> :
enum_traits<>::allow_bitops {};
constexpr my_enum foo = my_enum::Flag1 | my_enum::Flag2 | my_enum::Flag3;
As above(Kai) or do the following. Really enums are "Enumerations", what you want to do is have a set, therefore you should really use stl::set
enum AnimalFlags
{
HasClaws = 1,
CanFly =2,
EatsFish = 4,
Endangered = 8
};
int main(void)
{
AnimalFlags seahawk;
//seahawk= CanFly | EatsFish | Endangered;
seahawk= static_cast<AnimalFlags>(CanFly | EatsFish | Endangered);
}
Maybe like NS_OPTIONS of Objective-C.
#define ENUM(T1, T2) \
enum class T1 : T2; \
inline T1 operator~ (T1 a) { return (T1)~(int)a; } \
inline T1 operator| (T1 a, T1 b) { return static_cast<T1>((static_cast<T2>(a) | static_cast<T2>(b))); } \
inline T1 operator& (T1 a, T1 b) { return static_cast<T1>((static_cast<T2>(a) & static_cast<T2>(b))); } \
inline T1 operator^ (T1 a, T1 b) { return static_cast<T1>((static_cast<T2>(a) ^ static_cast<T2>(b))); } \
inline T1& operator|= (T1& a, T1 b) { return reinterpret_cast<T1&>((reinterpret_cast<T2&>(a) |= static_cast<T2>(b))); } \
inline T1& operator&= (T1& a, T1 b) { return reinterpret_cast<T1&>((reinterpret_cast<T2&>(a) &= static_cast<T2>(b))); } \
inline T1& operator^= (T1& a, T1 b) { return reinterpret_cast<T1&>((reinterpret_cast<T2&>(a) ^= static_cast<T2>(b))); } \
enum class T1 : T2
ENUM(Options, short) {
FIRST = 1 << 0,
SECOND = 1 << 1,
THIRD = 1 << 2,
FOURTH = 1 << 3
};
auto options = Options::FIRST | Options::SECOND;
options |= Options::THIRD;
if ((options & Options::SECOND) == Options::SECOND)
cout << "Contains second option." << endl;
if ((options & Options::THIRD) == Options::THIRD)
cout << "Contains third option." << endl;
return 0;
// Output:
// Contains second option.
// Contains third option.
C++20 Type-Safe Enum Operators
TL;DR
template<typename T>
requires std::is_enum_v<T> and
requires (std::underlying_type_t<T> x) {
{ x | x } -> std::same_as<std::underlying_type_t<T>>;
T(x);
}
T operator|(T left, T right)
{
using U = std::underlying_type_t<T>;
return T( U(left) | U(right) );
}
template<typename T>
requires std::is_enum_v<T> and
requires (std::underlying_type_t<T> x) {
{ x | x } -> std::same_as<std::underlying_type_t<T>>;
T(x);
}
T operator&(T left, T right)
{
using U = std::underlying_type_t<T>;
return T( U(left) & U(right) );
}
template<typename T>
requires std::is_enum_v<T> and requires (T x) { { x | x } -> std::same_as<T>; }
T & operator|=(T &left, T right)
{
return left = left | right;
}
template<typename T>
requires std::is_enum_v<T> and requires (T x) { { x & x } -> std::same_as<T>; }
T & operator&=(T &left, T right)
{
return left = left & right;
}
Rationale
With type trait std::is_enum we can test some type T for whether it is an enumeration type.
This includes both unscoped and scoped enums (i.e. enum and enum class).
With type trait std::underlying_type we can get the underlying type of an enum.
With C++20 concepts and constraints it is quite easy to then provide overloads for bitwise operations.
Scoped vs. Unscoped
If the operations should only be overloaded for either scoped or unscoped enums, std::is_scoped_enum can be used to extend the template constraints accordingly.
C++23
With C++23 we get std::to_underlying to convert an enum value to its underlying type more easily.
Move Semantics & Perfect Forwarding
Should you get in the bizarre situation that your underlying type has different semantics for copy vs. move or it does not provide a copy c'tor, then you should do perfect forwarding of the operands with std::forward.
You can use struct as follow:
struct UiFlags2 {
static const int
FULLSCREEN = 0x00000004, //api 16
HIDE_NAVIGATION = 0x00000002, //api 14
LAYOUT_HIDE_NAVIGATION = 0x00000200, //api 16
LAYOUT_FULLSCREEN = 0x00000400, //api 16
LAYOUT_STABLE = 0x00000100, //api 16
IMMERSIVE_STICKY = 0x00001000; //api 19
};
and use as this:
int flags = UiFlags2::FULLSCREEN | UiFlags2::HIDE_NAVIGATION;
So you don't need to int casting and it is directly usable.
Also it is scope separated like enum class
I prefer using magic_enum as it helps automate converting strings to enums and vice versa.
It is a header-only library which is written in C++17 standard.
magic_enum already has template functions for enum bitwise operators.
See documentation.
Usage:
#include <magic_enum.hpp>
enum Flag { ... };
Flag flag{};
Flag value{};
using namespace magic_enum::bitwise_operators;
flag |= value;

Should a friend operator in a class with enum parameters be found by Koenig lookup?

Consider the following code:
enum A : unsigned { a = 1, b = 2, c = 4 };
class B
{
friend constexpr A operator|(A a1, A a2)
{ return A(unsigned(a1) | unsigned(a2)); }
};
template <A a>
class C
{
};
int main()
{
C<a|c> c;
}
When compiled with g++ (4.8.1, -std=c++1), I get the following error:
test.C: In function ‘int main()’:
test.C:16:12: error: invalid conversion from ‘unsigned int’ to ‘A’ [-fpermissive]
C<a|c> c;
Which tells me that the operator is not being found. However, if the code is changed to:
enum A : unsigned { a = 1, b = 2, c = 4 };
constexpr A operator|(A a1, A a2)
{ return A(unsigned(a1) | unsigned(a2)); }
template <A a>
class C
{
};
int main()
{
C<a|c> c;
}
Then it compiles and runs fine. Is the error in the first case a compiler error, or I do misunderstand something? I would like to use the method of Boost.Operators to easily define operators by declaring a class with base classes from templates which define the operators, but this result precludes that in this case.
Thanks for any help.
Another way to solve it (other than jogojapan already mentioned), is to simply declare the friend function outside the scope.
enum A : unsigned { a = 1, b = 2, c = 4 };
//declaration
constexpr A operator|(A a1, A a2);
class B
{
//definition inside, ok.
friend constexpr A operator|(A a1, A a2)
{ return A(unsigned(a1) | unsigned(a2)); }
};
template <A a>
class C
{
};
int main()
{
C<a|c> c;
}
Okay, I took another approach, and here's code which solves my problem:
template <typename UNSIGNED>
struct BitwiseEnum
{
enum class Enum : UNSIGNED
{
};
constexpr static Enum value(unsigned bit)
{
return Enum(UNSIGNED(1) << bit);
}
friend constexpr Enum operator|(Enum a, Enum b)
{
return Enum(UNSIGNED(a)|UNSIGNED(b));
}
friend constexpr Enum operator&(Enum a, Enum b)
{
return Enum(UNSIGNED(a)&UNSIGNED(b));
}
friend constexpr Enum operator~(Enum a)
{
return Enum(~UNSIGNED(a));
}
};
class MyMask : public BitwiseEnum<unsigned long>
{
};
typedef MyMask::Enum Mask;
constexpr static Mask a = MyMask::value(0);
constexpr static Mask b = MyMask::value(1);
constexpr static Mask c = MyMask::value(2);
constexpr static Mask d = MyMask::value(3);
template <Mask A>
class B
{
};
int main()
{
B<a|b> test;
}
Now, when I defined a lot of enums like "MyMask", it can be done fairly simply, without much more code than a simply defined enum would have. And it behaves as one would "expect" from a bit field enum, can be used in strongly type checked template arguments, etc.