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
How to Write an Adl-Enabled Trailing Return Type, or Noexcept Specification
C++11 Constexpr Flatten List of Std::Array into Array
Portability of Native C++ Properties
Fatal Error C1010 - "Stdafx.H" in Visual Studio How Can This Be Corrected
Assigning a String of Characters to a Char Array
Get Current Working Directory in a Qt Application
Macro to Replace C++ Operator New
Send Email with Attachment in C++
Recognize Open and Closed Shapes Opencv
C++ Nested Classes Accessibility
Google Protocol Buffers on iOS
Convert Iso-8859-1 Strings to Utf-8 in C/C++
How to Use a C++11 to Program the Arduino
Stl Map Should Use Find() or [N] Identifier to Find Element in Map
Const Pointer Assign to a Pointer
Can Templates Be Used to Access Struct Variables by Name
Why Gcc Does Not Use Load(Without Fence) and Store+Sfence for Sequential Consistency