Implementation of Operators for Enum Class

Implementation of operators for enum class

The no-cast solution is to use switch. However, you can generate a pseudo-switch using templates. The principle is to recursively process all values of the enum using a template list (or a parameter pack). So, here are 3 methods I found.

Test enum:

enum class Fruit
{
apple,
banana,
orange,
pineapple,
lemon
};

The vanilla switch (live here):

Fruit& operator++(Fruit& f)
{
switch(f)
{
case Fruit::apple: return f = Fruit::banana;
case Fruit::banana: return f = Fruit::orange;
case Fruit::orange: return f = Fruit::pineapple;
case Fruit::pineapple: return f = Fruit::lemon;
case Fruit::lemon: return f = Fruit::apple;
}
}

The C++03-ish method (live here):

template<typename E, E v>
struct EnumValue
{
static const E value = v;
};

template<typename h, typename t>
struct StaticList
{
typedef h head;
typedef t tail;
};

template<typename list, typename first>
struct CyclicHead
{
typedef typename list::head item;
};

template<typename first>
struct CyclicHead<void,first>
{
typedef first item;
};

template<typename E, typename list, typename first = typename list::head>
struct Advance
{
typedef typename list::head lh;
typedef typename list::tail lt;
typedef typename CyclicHead<lt, first>::item next;

static void advance(E& value)
{
if(value == lh::value)
value = next::value;
else
Advance<E, typename list::tail, first>::advance(value);
}
};

template<typename E, typename f>
struct Advance<E,void,f>
{
static void advance(E& value)
{
}
};

/// Scalable way, C++03-ish
typedef StaticList<EnumValue<Fruit,Fruit::apple>,
StaticList<EnumValue<Fruit,Fruit::banana>,
StaticList<EnumValue<Fruit,Fruit::orange>,
StaticList<EnumValue<Fruit,Fruit::pineapple>,
StaticList<EnumValue<Fruit,Fruit::lemon>,
void
> > > > > Fruit_values;

Fruit& operator++(Fruit& f)
{
Advance<Fruit, Fruit_values>::advance(f);
return f;
}

The C++11-ish method (live here):

template<typename E, E first, E head>
void advanceEnum(E& v)
{
if(v == head)
v = first;
}

template<typename E, E first, E head, E next, E... tail>
void advanceEnum(E& v)
{
if(v == head)
v = next;
else
advanceEnum<E,first,next,tail...>(v);
}

template<typename E, E first, E... values>
struct EnumValues
{
static void advance(E& v)
{
advanceEnum<E, first, first, values...>(v);
}
};

/// Scalable way, C++11-ish
typedef EnumValues<Fruit,
Fruit::apple,
Fruit::banana,
Fruit::orange,
Fruit::pineapple,
Fruit::lemon
> Fruit_values11;

Fruit& operator++(Fruit& f)
{
Fruit_values11::advance(f);
return f;
}

(C++11-ish old version)

You may be able to extend by adding some preprocessor to remove the need to repeat the list of values.

Operator overloading of enum class in class

You might use friend functions:

class test
{
private:

enum class Loc : bool{
fwrd = true,
bkrd = false
};
friend Loc operator!(Loc loc){
return Loc(!bool(loc));
}
Loc doSomething(Loc loc){
return !loc;
}
};

Demo

How to overload |= operator on scoped enum?

inline NumericType& operator |=(NumericType& a, NumericType b)
{
return a= a |b;
}

This works? Compile and run: (Ideone)

#include <iostream>
using namespace std;

enum class NumericType
{
None = 0,

PadWithZero = 0x01,
NegativeSign = 0x02,
PositiveSign = 0x04,
SpacePrefix = 0x08
};

inline NumericType operator |(NumericType a, NumericType b)
{
return static_cast<NumericType>(static_cast<int>(a) | static_cast<int>(b));
}

inline NumericType operator &(NumericType a, NumericType b)
{
return static_cast<NumericType>(static_cast<int>(a) & static_cast<int>(b));
}

inline NumericType& operator |=(NumericType& a, NumericType b)
{
return a= a |b;
}

int main() {
// your code goes here
NumericType a=NumericType::PadWithZero;
a|=NumericType::NegativeSign;
cout << static_cast<int>(a) ;
return 0;
}

print 3.

Operator overloading enum class

The compiler is telling exactly what's wrong. You didn't overload &=.

Despite the expected semantics, &= doesn't automatically expand to a = a & Numbers::one;

If you want to have both, the canonical way is to usually implement op in terms of op=. So your original function is adjusted as follows:

inline int& operator &=(int& a, Numbers b)
{ // Note the pass by reference
return (a &= static_cast<int>(b));
}

And the new one uses it:

inline int operator &(int a, Numbers b)
{ // Note the pass by value
return (a &= b);
}

Scoped Enums (enum class) relational operators

To complete the picture and confirm that yes, the ordering is defined. We start with why one may put two enumerators in a relational expression...

[expr.rel]

2 The usual arithmetic conversions are performed on operands of
arithmetic or enumeration type...

5 If both operands (after conversions) are of arithmetic or
enumeration type, each of the operators shall yield true if the
specified relationship is true and false if it is false.

... where the usual arithmetic conversion for a scoped enumeration is a no-op...

[expr]

9 Many binary operators that expect operands of arithmetic or
enumeration type cause conversions and yield result types in a similar
way. The purpose is to yield a common type, which is also the type of
the result. This pattern is called the usual arithmetic conversions,
which are defined as follows:

  • If either operand is of scoped enumeration type ([dcl.enum]), no conversions are performed; if the other operand does not have the same
    type, the expression is ill-formed.

So they do not convert, and may only be compared to an object of the same exact type. The values given to the enumerators (as specified by the other answer) are what determines if "each of the operators shall yield true if the specified relationship is true and false if it is false". That's how the comparison is done.

It's also worth noting that enumeration type variables can take values that are not enumerated! So for instance...

enum class foo {
min, max = 10
};

foo mid = static_cast<foo>(5);

... is valid, and the comparison mid > foo::min will hold just the same, because the preceding paragraph is generalized to include more than just the named values.

Defining operators for enums nested within a class

The operator you defined inside the class applies to the class Example and therefore having an argument and return type of E& is incorrect and the compiler tells you so.

The standard tell us that:

An operator function shall either be a non-static member function or be a non-member function[...]

it can't be a non-static member function of E therefore it has to be a non-member function.

You can define the operator outside of Example as follows:

Example::E& operator++(Example::E& e) {
// modify e
return e ;
}

Overloading cast operator for enum class

You should look into overloading the enum class as an integer (this is a C++ 11 feature).

enum class tetroType : int {
I = 1, O = 2, T = 3, J = 4, L = 5, S = 6, Z = 7, NONE
};

enum class gridBlock : int {
Blue = 1, Green = 2, Orange = 3, Purple = 4, Red = 5, Teal = 6, Yellow = 9, EMPTY
};

From here you can write a basic conversion using ether C Style typecasting, or static_cast

gridBlock ConvertTetro(tetroType type){
return static_cast<gridBlock>(static_cast<int>(type));
}

gridBlock ConvertTetro(tetroType type){
return (gridBlock)((int)((type)));
}

this will match any grid block to equal tetrotypes, and will default to gridBlock::EMPTY if theres no matching type. This function should be pretty easy to figure out how to go the other way if needed. From here you need to match up the int values between the two.

You can also use char values as char literals ('A', 'b', '!') using

enum class enumName : char

This will work as long as the two underlying types

Operator overloading on an enum nested in a class

This compiles, but does not link!

Compile but doesn't link because you declare a non-template operator (it's inside a template struct but isn't a template function)

friend enumenum operator~(enumenum a);

and you define a template one

template <typename T>
typename dummy<T>::enumenum
operator~(typename dummy<T>::enumenum a) {
return static_cast<typename dummy<T>::enumenum>(~a);
}

and a template definition can't match a non-template declaration.

You could try to declare the function as a template one

template <typename T>
struct dummy
{
enum enumenum { a = 1, b = 2, c = 4 };

template <typename U>
friend typename dummy<U>::enumenum
operator~ (typename dummy<U>::enumenum const & a);
};

template <typename T>
typename dummy<T>::enumenum
operator~ (typename dummy<T>::enumenum const & a)
{ return static_cast<typename dummy<T>::enumenum>(~a); }

int main ()
{
auto a = ~dummy<double>::a;
}

but, unfortunately, this compile but, calling the ~ operator as follows

 ~dummy<double>::a;

isn't called the template function because the template parameter T can't be deduced because is in not-deduced-context (before the last ::), as pointed by Benny K in a comment.

So, instead the template operator~(), the dummy<double>::a is converted to int and the ~ operator for int is applied (with type result int).

You can verify this point explicitly calling a function operator~()

 auto a = operator~(dummy<double>::a); 

You should get a "no matching function for call to 'operator~'" error (with note "note: candidate template ignored: couldn't infer template argument 'T'") or something similar.

To make this solution works, you have to explicate the type of the class, to avoid the template deduction

 auto a = operator~<double>(dummy<double>::a); 

and, now, you can verify that a is a dummy<double>::enumenum

 static_assert( std::is_same<decltype(a), dummy<double>::enumenum>::value, "!" );

But, obviously, this isn't a satisfactory solution (and very dangerous, if you forget to avoid the simple use of ~).

Otherwise you can define the operator as non-template

template <typename T>
struct dummy
{
enum enumenum { a = 1, b = 2, c = 4 };

friend enumenum operator~ (enumenum const & a);
};

dummy<double>::enumenum
operator~(dummy<double>::enumenum const & a)
{ return static_cast<dummy<double>::enumenum>(~a); }

int main ()
{
auto a = ~dummy<double>::a;
}

but you have to define a different operator for every dummy<T> type.

IMHO the most simple, safe and elegant solution is your working one: declare/define the operator inside the struct.

Implement comparison operator for Enum type in python3

Enum subclasses are somewhat special in that all enumeration values become instances of the class (with a few tweaks). This does mean you can 'just' define a normal method on the Enum subclass and they'll be available on each enumeration value.

This applies to special methods like object.__le__() too; just define it as a regular method, not a classmethod:

class AB(enum.Enum):
def __le__(self, b):
return self.value <= b.value

a = 1
b = 2
c = 3
d = 4
e = 5

Note that I used the instance attribute .value, just like you can do AB.a.value.

You could also use the IntEnum class; that makes each enumeration value a subclass of int, and they can be compared naturally:

class AB(enum.IntEnum):
a = 1
b = 2
c = 3
d = 4
e = 5

Demo:

>>> import enum
>>> class AB(enum.Enum):
... def __le__(self, b):
... return self.value <= b.value
... a = 1
... b = 2
... c = 3
... d = 4
... e = 5
...
>>> AB.a <= AB.b
True
>>> AB.b <= AB.a
False
>>> AB.a < AB.b
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unorderable types: AB() < AB()

and using IntEnum as the base:

>>> class AB(enum.IntEnum):
... a = 1
... b = 2
... c = 3
... d = 4
... e = 5
...
>>> AB.a <= AB.b
True
>>> AB.b >= AB.a
True
>>> AB.b > AB.a
True
>>> AB.a + AB.b
3


Related Topics



Leave a reply



Submit