Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

enum class or enum?

100 views
Skip to first unread message

JiiPee

unread,
Jul 15, 2020, 12:18:43 PM7/15/20
to
Quick question. Sometimes I think whether to use enum class or enum.
enum is shorter, so is it sometimes better?

Example a tic tac toe game where board piece is enum:

enum class Piece {Empty, X, O};

    std::vector<Piece> board;
    board[4] = Piece::X;


Would this be better:

enum Piece {Empty, X, O};

    std::vector<Piece> board;
    board[4] = X;

So that things are more compact? Putting Piece::X makes things a bit too
long? I know its safer, but also it makes things longer...

Paavo Helde

unread,
Jul 15, 2020, 12:56:26 PM7/15/20
to
Depens on the project scope. If this is a hundred line program developed
during a weekend, then plain enum is fine. If this is a million-line
program developed over decades, I would advocate for enum class.


Bonita Montero

unread,
Jul 15, 2020, 1:25:46 PM7/15/20
to
If the enum is scoped inside a class anyway you might not use enum
class.

JiiPee

unread,
Jul 15, 2020, 2:08:37 PM7/15/20
to
On 15/07/2020 18:25, Bonita Montero wrote:
> If the enum is scoped inside a class anyway you might not use enum
> class.


yes this is another question I ve been thinking :).

But still, using enum class is safer always than enum. So even inside a
class enum class would be safer... but I guess your point is that the
class is small so no need to be super safe?

Mr Flibble

unread,
Jul 15, 2020, 2:29:58 PM7/15/20
to
Often when you have an enum inside a class it is hard to think of a name for the enum that is different to the name of the class; same problem with putting enum outside of class so in this instance normal enum inside class is superior.

Sausages.

/Flibble

--
"Snakes didn't evolve, instead talking snakes with legs changed into snakes." - Rick C. Hodgin

“You won’t burn in hell. But be nice anyway.” – Ricky Gervais

“I see Atheists are fighting and killing each other again, over who doesn’t believe in any God the most. Oh, no..wait.. that never happens.” – Ricky Gervais

"Suppose it's all true, and you walk up to the pearly gates, and are confronted by God," Byrne asked on his show The Meaning of Life. "What will Stephen Fry say to him, her, or it?"
"I'd say, bone cancer in children? What's that about?" Fry replied.
"How dare you? How dare you create a world to which there is such misery that is not our fault. It's not right, it's utterly, utterly evil."
"Why should I respect a capricious, mean-minded, stupid God who creates a world that is so full of injustice and pain. That's what I would say."

Bo Persson

unread,
Jul 16, 2020, 3:32:10 AM7/16/20
to
Who says that shorter is better?

Using P and b, instead of Piece and board, would make it even shorter -
but in no way better.



Bo Persson

Juha Nieminen

unread,
Jul 16, 2020, 4:09:34 AM7/16/20
to
JiiPee <n...@notvalid.com> wrote:
> Quick question. Sometimes I think whether to use enum class or enum.

Old-style enum, which was inherited from C, is essentially just almost purely
syntactic sugar for declaring compile-time int constants. While not exactly
the same thing (even in C), an enum like

enum Name { value1, value2, value3 };

is almost the same thing as saying

typedef int Name;
const int value1 = 0, value2 = 1, value3 = 2;

(Yes, it's not *exactly* the same thing, even in C, but in most practical
situations you can consider them the same thing.)

In most situations this is a bit problematic because all those names end up
in the surrounding scope (often the global namespace, if you declare that
enum in that scope). In order to minimize naming collisions you usually want
to manually prefix all those names, by naming them like

enum Name { Name_value1, Name_value2, Name_value3 };

or similar.

Strongly-typed enums (ie. "enum class") add modularity by not contaminating
the surrounding scope with all those names, and make the enumerated type an
actual user-defined type, rather than it being just an alias for an int.

Nevertheless, there are situations where old-style enums can be more
practical. After all, they are just effectively ints, and sometimes that's
useful. Namely, you can directly do arithmetic with them, while the same is
not possible (on purpose) with strongly-typed enums, without an explicit
cast to int (which makes it more awkward).

Most particularly, old-style enumerated values can be used as-is to index
an array, while strongly-typed enumerated values cannot (without an explicit
cast). Sometimes being able to index an array with enumerated names can be
handy (when those names refer to elements of an array).

Unfortunately there is no best-of-both-worlds alternative, ie. a "mixed"
style enumerated value which are inside the namespace scope of the enum
type but can be be used for integer arithmetic and array indexing as-is
without an explicit cast.

I suppose the closest you can get to that is by putting the old-style
enum inside a namespace (but then you can't use the name of that
namespace as the name of the enumerated type).

JiiPee

unread,
Jul 16, 2020, 3:17:51 PM7/16/20
to
On 16/07/2020 09:09, Juha Nieminen wrote:
> JiiPee <n...@notvalid.com> wrote:
>> Quick question. Sometimes I think whether to use enum class or enum.
> Old-style enum, which was inherited from C, is essentially just almost purely
> syntactic sugar for declaring compile-time int constants. While not exactly
> the same thing (even in C), an enum like
>
> enum Name { value1, value2, value3 };
>
> is almost the same thing as saying
>
> typedef int Name;
> const int value1 = 0, value2 = 1, value3 = 2;
>
> (Yes, it's not *exactly* the same thing, even in C, but in most practical
> situations you can consider them the same thing.)


yes


>
> In most situations this is a bit problematic because all those names end up
> in the surrounding scope (often the global namespace, if you declare that
> enum in that scope). In order to minimize naming collisions you usually want
> to manually prefix all those names, by naming them like
>
> enum Name { Name_value1, Name_value2, Name_value3 };
>
> or similar.
>
> Strongly-typed enums (ie. "enum class") add modularity by not contaminating
> the surrounding scope with all those names, and make the enumerated type an
> actual user-defined type, rather than it being just an alias for an int.
>
> Nevertheless, there are situations where old-style enums can be more
> practical. After all, they are just effectively ints, and sometimes that's
> useful. Namely, you can directly do arithmetic with them, while the same is
> not possible (on purpose) with strongly-typed enums, without an explicit
> cast to int (which makes it more awkward).
>
> Most particularly, old-style enumerated values can be used as-is to index
> an array, while strongly-typed enumerated values cannot (without an explicit
> cast). Sometimes being able to index an array with enumerated names can be
> handy (when those names refer to elements of an array).


ok, this I also have been thinking. enum class makes it a bit difficult



Juha Nieminen

unread,
Jul 17, 2020, 1:56:28 AM7/17/20
to
JiiPee <n...@notvalid.com> wrote:
>> Most particularly, old-style enumerated values can be used as-is to index
>> an array, while strongly-typed enumerated values cannot (without an explicit
>> cast). Sometimes being able to index an array with enumerated names can be
>> handy (when those names refer to elements of an array).
>
> ok, this I also have been thinking. enum class makes it a bit difficult

Not difficult, just a bit annoying that you need to explicitly cast the name,
eg. like

value = table[unsigned(enumeratedName)];

JiiPee

unread,
Jul 17, 2020, 6:34:24 AM7/17/20
to
value = table[North];

vs

value = table[unsigned(Direction::North)];

If that is done alot in the code the second one is not so nice.

But

Direction curdir = Direction::North;

is fine,... its just that as an index it gives troubles.



Thiago Adams

unread,
Jul 17, 2020, 2:19:33 PM7/17/20
to
If you write a library and publish it you will not know
where this library will be used. In this scenario extra care
is taken to avoid name conflicts. This is not only for enuns but
any variable. Namespaces can be used in C++ and suffixes in C.

In my opinion beautiful code is when you look at the source code
and everything looks to be created in one shot by the same person.

This is not always possible to have. Different programmers,
different libraries and styles can live inside the same source
code.

My advice:

If you are writing the code for yourself or your company,
(not for publishing a library) then keep everything small.

The primarily characteristic you need is "easy to change" and
not "protect for the unknown".



















Paavo Helde

unread,
Jul 17, 2020, 3:27:50 PM7/17/20
to
If you need to change something related to enums, the hard part is not
the length of names to be typed. You know, there are things like
autocompletion menus, copy-paste, find-and-replace, etc.

The hard part is to ensure that after the changes the program still
works correctly. For example, you might change a function parameter from
enum to bool. Guess what? A call with plain enum value still compiles
and most probably does not do the right thing. Enum class will fail to
compile, this is a major win in the "easy to change" compartment.

Mr Flibble

unread,
Jul 17, 2020, 3:43:21 PM7/17/20
to
On 15/07/2020 17:18, JiiPee wrote:
> Quick question. Sometimes I think whether to use enum class or enum. enum is shorter, so is it sometimes better?
>
> Example a tic tac toe game where board piece is enum:
>
> enum class Piece {Empty, X, O};

I would think long and hard about making "Empty" a "Piece".

Keith Thompson

unread,
Jul 17, 2020, 4:02:57 PM7/17/20
to
If you're using it as an index, you can write an overloaded
operator[] that accepts an operand of your enum class type and *not*
of any integral type. You'd have to create your own array-like
class rather than using raw arrays or std::vector. Like many things,
it's a tradeoff between convenience and safety.

--
Keith Thompson (The_Other_Keith) Keith.S.T...@gmail.com
Working, but not speaking, for Philips Healthcare
void Void(void) { Void(); } /* The recursive call of the void */

Thiago Adams

unread,
Jul 17, 2020, 4:52:14 PM7/17/20
to
On Friday, July 17, 2020 at 4:27:50 PM UTC-3, Paavo Helde wrote:
...
> The hard part is to ensure that after the changes the program still
> works correctly. For example, you might change a function parameter from
> enum to bool. Guess what? A call with plain enum value still compiles
> and most probably does not do the right thing. Enum class will fail to
> compile, this is a major win in the "easy to change" compartment.

I will tell what I do in this case.

If I need to change something that changes the function
contract I rename that function and compile again.
Doing this ensures that I will review all callers.
When I am satisfied with the review I put the original
name back.

The approach is more generic than only prevent wrong
conversion between enum and bool.

Thiago Adams

unread,
Jul 17, 2020, 5:12:56 PM7/17/20
to
On Wednesday, July 15, 2020 at 1:18:43 PM UTC-3, JiiPee wrote:
> Quick question. Sometimes I think whether to use enum class or enum.
> enum is shorter, so is it sometimes better?
>
> Example a tic tac toe game where board piece is enum:
>
> enum class Piece {Empty, X, O};
[...]

Using 'Empty' here will probably cause a conflict.

enum A {Empty, A1, A2};
enum B {Empty, B1, B2};

Once I have suggested at comp lang c a feature for C
that gives bigger char literals.

Today we can use like this:

int c = 'abcd'; //up to four chars (int)

and this will create a unique value.

How we could add more?

My suggestion was to create a hash that give the same result
as it is today until 4 chars. After that we hash differently
but universally (all compilers would do the same)

What is the relation with enums?

We could have a :

enum Color {
'blue',
'red',
'yellow'
};

And we could reuse 'red'

enum Alarm
{
'red'
'yellow'
};

enum Alarm a = 'red';
a = 'blue'; //error blue is not a valid alarm value

enum Color c = 'red';

In case 'red' and 'yellow' give us the same hash
then this would be a compiler error at color enum.

This is a property similar of we had for nullptr. nullptr
is a constant that can be applied for any pointer type.

struct X* pX = nullptr;
struct Y* pY = nullptr;

for those enuns types 'red' for instance can be applied
for any enum that have 'red' in their list.

So, here if we want to use the world 'empty ' this could
be used in any enum according with the context instead
of E1::Empty and E2::Empty;

This is also a reson for people use int or #defines instead
of enums.
int makes the 'set' of values open.
For instance;

#define ERROR1 1
#define ERROR2 2
#define ERROR3 3

int F1(); //returns ERROR1 or ERROR2
int F2(); //returns ERROR3 or ERROR2

using enuns to represent each set of errors
we cannot have the same values shared.







Keith Thompson

unread,
Jul 17, 2020, 6:54:26 PM7/17/20
to
Thiago Adams <thiago...@gmail.com> writes:
> On Wednesday, July 15, 2020 at 1:18:43 PM UTC-3, JiiPee wrote:
>> Quick question. Sometimes I think whether to use enum class or enum.
>> enum is shorter, so is it sometimes better?
>>
>> Example a tic tac toe game where board piece is enum:
>>
>> enum class Piece {Empty, X, O};
> [...]
>
> Using 'Empty' here will probably cause a conflict.
>
> enum A {Empty, A1, A2};
> enum B {Empty, B1, B2};

Not if you use "enum class".

> Once I have suggested at comp lang c a feature for C
> that gives bigger char literals.
>
> Today we can use like this:
>
> int c = 'abcd'; //up to four chars (int)
>
> and this will create a unique value.

There's no guarantee that the value is unique (or that int is wider
than 16 bits).

I suppose you *could* modify the language to provide more guarantees
for multi-character constants, but my own inclination is to avoid
them, and possibly deprecate or remove them in a future standard.

[...]

already...@yahoo.com

unread,
Jul 19, 2020, 6:22:10 AM7/19/20
to
Looks more like a tradeoff between convenience and inconvenience :-)
There are people that like to suffer, but even these people don't like to suffer too much, so for them it could be called a tradeoff.

Thiago Adams

unread,
Jul 20, 2020, 10:14:19 AM7/20/20
to
On Friday, July 17, 2020 at 7:54:26 PM UTC-3, Keith Thompson wrote:
> Thiago Adams writes:
> > On Wednesday, July 15, 2020 at 1:18:43 PM UTC-3, JiiPee wrote:
> >> Quick question. Sometimes I think whether to use enum class or enum.
> >> enum is shorter, so is it sometimes better?
> >>
> >> Example a tic tac toe game where board piece is enum:
> >>
> >> enum class Piece {Empty, X, O};
> > [...]
> >
> > Using 'Empty' here will probably cause a conflict.
> >
> > enum A {Empty, A1, A2};
> > enum B {Empty, B1, B2};
>
> Not if you use "enum class".
>
> > Once I have suggested at comp lang c a feature for C
> > that gives bigger char literals.
> >
> > Today we can use like this:
> >
> > int c = 'abcd'; //up to four chars (int)
> >
> > and this will create a unique value.
>
> There's no guarantee that the value is unique (or that int is wider
> than 16 bits).
>
> I suppose you *could* modify the language to provide more guarantees
> for multi-character constants, but my own inclination is to avoid
> them, and possibly deprecate or remove them in a future standard.
>
> [...]
>

Yes this feature is not well defined.
I haven't seen any use and I would not use myself unless
it was more 'official' and common.

I just want to add here (before I forgot) the motivation
for the 'literals'.

I was working in a json parser and I had a enum like this:

enum JSToken {
TK_LEFT_SQUARE_BRACKET, // [
TK_RIGHT_SQUARE_BRACKET, // ]
TK_NUMBER, // [0..9]+ etc...
...
};

When parsing I need to compare:

if (token == TK_LEFT_SQUARE_BRACKET){ ... }
or
if (token == TK_NUMBER){ ... }

In this case it would be much more natural to have:

if (token == '[') { ... }

but for number there is no character,
then I needed something like :

if (token == 'number'){...}

to make both codes homogeneous.

I considered this alternative:

enum JSToken {
TK_LEFT_SQUARE_BRACKET = '['
TK_RIGHT_SQUARE_BRACKET = ']'
TK_NUMBER = 200,
};

In this case I could use '[' instead of TK_LEFT_SQUARE_BRACKET but
it fells like something that can go wrong.

Thiago Adams

unread,
Jul 20, 2020, 2:14:07 PM7/20/20
to
On Monday, July 20, 2020 at 11:14:19 AM UTC-3, Thiago Adams wrote:
...
> I just want to add here (before I forgot) the motivation
> for the 'literals'.
>
> I was working in a json parser and I had a enum like this:
>
> enum JSToken {
> TK_LEFT_SQUARE_BRACKET, // [
> TK_RIGHT_SQUARE_BRACKET, // ]
> TK_NUMBER, // [0..9]+ etc...
> ...
> };
>
> When parsing I need to compare:
>
> if (token == TK_LEFT_SQUARE_BRACKET){ ... }
> or
> if (token == TK_NUMBER){ ... }
>
> In this case it would be much more natural to have:
>
> if (token == '[') { ... }
>

C++ 11 has the feature 'User-defined literals' using together
with constexpr the final result is similar of what I have
suggested.

I can use a hash, or in this case for tokens, I can
define my value for each.

For instance:


constexpr int operator "" _tk(const char* s, size_t sz) {

if (s[0] == 't' && s[1] == 'r' && s[2] == 'u' && s[3] == 'e' && s[4] == '\0')
return 1;
else if (s[0] == 'f' && s[1] == 'a' && s[2] == 'l' && s[3] == 's' && s[4] == 'e' && s[5] == '\0')
return 2;
//else
// static_assert(false, "not defined"); //not working?

return 0;
}

template<char...> int operator "" _tk(); // Literal operator template

int main()
{
static_assert("true"_tk == 1);
static_assert("false"_tk == 2);
}

it can be used like:

if (token == "true"_tk) {...}


Or something more 'basic'.


constexpr int token(const char* s) {

if (s[0] == 't' && s[1] == 'r' && s[2] == 'u' && s[3] == 'e' && s[4] == '\0')
return 1;
else if (s[0] == 'f' && s[1] == 'a' && s[2] == 'l' && s[3] == 's' && s[4] == 'e' && s[5] == '\0')
return 2;
//else
// static_assert(false, "not defined");

return 0;
}

int main()
{
static_assert(token("true") == 1);
static_assert(token("false") == 2);
}

if (token == token("true")) {...}
if (token == token("[")) {...}

(In C++ I would use this form)

---


Thinking in terms of C this also could be archived with
a new preprocessor feature that is literals expansion.
Like this:

#define TOKEN("true") 1
#define TOKEN("[") 2

//TOKEN("true") expands to 1
//TOKEN("[") expands to 2

if (token == TOKEN("true")) {...}
if (token == TOKEN("[")) {...}

of course if we had just names the simplest solution would be

#define TK_TRUE 1

but using [ it is not possible




0 new messages