#enum inside struct vs inside name space

68 messages · Page 1 of 1 (latest)

cobalt warren
#

So i understand that before a certain C++ verison where scoped enums existed, people simulated the behavior by nested an enum inside a struct, but I also thought about why they didnt just put it inside of a namespace. I found that it is because putting it inside of a struct has type saftey where as a namespace doesnt but I am confused on how this works? I know that if you nest types inside of classes, the class just becomes essentially a namespace for the nested type but how does it provide type safety?

mortal marshBOT
#

When your question is answered use !solved or the button below to mark the question as resolved.

Remember to ask specific questions, provide necessary details, and reduce your question to its simplest form. For tips on how to ask a good question use !howto ask.

crude fern
cobalt warren
#

in the case of nesting an unscoped in enum in a struct to simulate a scoped enum. Id be looking to use it outside the struct

brave latch
#

Specifically, people often made the class type have a member variable that stored the enum itself

#

And also add things like operator< or whatever they needed to it

cobalt warren
#

im confused looking at the proposal

#

it has

#

typedef enum Alert { CndGreen, CndYellow, CndRed };

#

what is the purpose of this? it declares a type def that has no name

#

wouldnt it be the same as enum Alert { CndGreen, CndYellow, CndRed };

brave latch
#

In C, it was different

cobalt warren
#

something like typedef enum Alert { CndGreen, CndYellow, CndRed } Alert;

#

makes sense to me

brave latch
#

If you didn't use the typedef in C, then you'd have to say enum Alert every time you wanted to name it

#

same with struct

cobalt warren
#

yes

#

but in c it would need to be like this no?

typedef enum Alert { CndGreen, CndYellow, CndRed } Alert;

#

it allows you to use Alert and also enum Alert

#

unless I am mis understanding the purpose of:
typedef enum Alert { CndGreen, CndYellow, CndRed }

i think it would only allow you to do enum Alert since the typedef doesnt have a name?

brave latch
#

It's possible that the proposal may have a typo, I'd think it should be typedef enum { .... } Alert;

#

Other parts of the proposal just do enum Color_ { ...};

shell basin
cobalt warren
shell basin
#

;compile

enum class fruit { apple, orange };

int main()
{
  int i = fruit::apple;
}
tawny coralBOT
#
Compiler Output
<source>: In function 'int main()':
<source>:5:18: error: cannot convert 'fruit' to 'int' in initialization
    5 |   int i = fruit::apple;
      |           ~~~~~~~^~~~~
      |                  |
      |                  fruit
Build failed
cobalt warren
#

right

shell basin
#

I'm doing it the wrong way around

cobalt warren
#

lol

#

i think i understand that

#

but I am more so confused on why (pre scoped enums) wrapping it in a struct creates type safety and wraping it in a namespace doesnt

shell basin
#

anyway, that's not something you can achieve by just plopping a plain enum inside a namespace

#

;compile

namespace fruit
{
  enum whatever { apple, orange };
}

int main()
{
  int i = fruit::apple;
}
tawny coralBOT
#
Compilation successful
shell basin
#

does this clear anything about your confusion

crude fern
#

oh wait, i not understand question at all

shell basin
#

if that's not clear, then do you expect the code below to work

struct fruit
{
  int data = 0;
};

int main()
{
  int i = fruit{};
}

because if you do, then we need to start from there

cobalt warren
# shell basin does this clear anything about your confusion

Okay so at first I understood it. Now I am trying it and I am confused. I understand that if you plop an enum into a namespace it still implicitly converts to int, if you use a scoped enum it doesn’t implicitly convert to int, but if you plop an enum inside of a struct, it still implicitly converts to int. You were saying that putting it inside a struct would create type safety but this code compiles fine:


struct test{
  private:
  test ();
  public:

  enum color {RED, BLUE};

};
int main() {
  test:: color x = test::BLUE; //works
  int y = test::BLUE; //works
  return 0;
}
#

Doing above is essentially the same thing as this no?:


namespace Test{
  enum color{RED,BLUE};
}
int main() {
  test:: color x = test::BLUE; //works
  int y = test::BLUE; //works
  return 0;
}
shell basin
#

and not what I said to "do" when using a struct

#

;compile

struct fruit
{
  int data = 0;
};

int main()
{
  int i = fruit{};
}
tawny coralBOT
#
Compiler Output
<source>: In function 'int main()':
<source>:8:11: error: cannot convert 'fruit' to 'int' in initialization
    8 |   int i = fruit{};
      |           ^~~~~~~
      |           |
      |           fruit
Build failed
shell basin
#

and if you're thinking "but that's not the interface/syntax of an enum", that's because I can't be bothered to complete the thing

#

and you're also just not gonna get "all around nice syntax" trying to reimplement a scoped enum without scoped enum

cobalt warren
# shell basin sure, but that's also literally not what I wrote

I know and I apologize for the confusion. I understand scoped enums, but my confusion was pooping an enum in a struct vs ploping an enum in a name space and I thought you answered that but when I was looking at your code you were using an enum plopped inside a namespace and just a regular struct which I know they don’t convert

brave latch
#

The proposals I linked earlier show what is possible when using the "enum in a struct" thing

#

People doing operator overloads and preventing implicit casting is only possible if you can only use the enum through the struct/class

#

And that's essentially the entire motivation for why enum class was introduced in the first place

shell basin
#

this indirectly goes back to my point about what scoped enum actually do/change

#

I personally don't care much about having to do fruit::apple rather than directly apple, enforcing a "longer name" for enum to prevent name collision and whatnot already has solutions in the language that wouldn't require introducing "scoped enum" on top of "unscoped enum"

#

as far as I'm concerned the bigger point is and has always been about conversions

#

and my example about putting an unscoped enum in a namespace is specifically to show that this does nothing for conversions

shell basin
#

;compile

class color
{
    int data;

public:
    color() = default;

    explicit color(int value) : data(value) {}
    explicit operator int() const { return data; }

    static color RED() { return color{0}; }
    static color BLUE() { return color{1}; }
};

int main()
{
    color c = color::RED();
    int i = color::RED();
}
tawny coralBOT
#
Compiler Output
<source>: In function 'int main()':
<source>:18:23: error: cannot convert 'color' to 'int' in initialization
   18 |     int i = color::RED();
      |             ~~~~~~~~~~^~
      |                       |
      |                       color
<source>:9:14: note: explicit conversion function was not considered
    9 |     explicit operator int() const { return data; }
      |              ^~~~~~~~
Build failed
shell basin
#

this is closer to the kind of thing you need to do if you want behaviour similar to a scoped enum, without a scoped enum

cobalt warren
#

ohh okay i see now

#

that makes alot of sense

#

thanks

mortal marshBOT
#

@cobalt warren Has your question been resolved? If so, type !solved :)