-5

While tying my hands on enum I found that:

  1. enum can't be assigned any literal (even of integral types).

    enum sign{alpha,beta};
    alpha=4;       //error: lvalue required as left operand of assignment
    

Regarding this I can't understand how enum is not a lvalue since it has a name (identifier).

  1. In C++ Primer it has been given that:

An object of enumeration type may be initialized or assigned only by one of its enumerators or by another object of the same enumeration type.

It has also shown in an example that:

enum p1{var1A,var1B};
enum p2{var2A,var2B};

var2A=var1A //Error: var2A is not a p2 enumerator -> as written in the book
var2A=var2B //Correct as per the book

But why on assigning the correct value all I am getting is the same lvalue error which is being shown in point 1.

Gaurav
  • 1,570
  • 5
  • 17
  • 4
    "An object of enumeration type" is not the same as an "enumerator". You are trying to assign a value to an enumerator, not an object of enumeration type. Compare: `sign s; s = alpha;` – Sami Hult Jan 06 '19 at 13:58
  • It has a name, but it cannot be assigned a new one, as it has a constant value by construction (here 0). Change your book, throw it is a fire. – Matthieu Brucher Jan 06 '19 at 13:58
  • `alfa` is not a lvalue, only lvalue can be assigned – bruno Jan 06 '19 at 13:59
  • When using C++ you should generally prefer `enum class` over plain `enum`. – Jesper Juhl Jan 06 '19 at 14:36
  • @JesperJuhl is it a part of version before c++11? (as the project I am working on requires that). – Gaurav Jan 06 '19 at 15:43

3 Answers3

1

You can initialize your enumerators inside the enumerator-list, not outside of it:

enum sign { alpha = 4, beta };

alfa is not a "an object of enumeration type", it's an enumerator. If you had:

sign myenum;

then myenum would be "an object of enumeration type" and then you could do:

myenum = alpha;

or:

myenum = beta;

If you really want to go down that route, then use scoped enums (whose underlying type you can specify) and some std::underlying_type magic as a workaround:

enum class p1 { var1A, var1B };
enum class p2 : std::underlying_type<p1>::type { var2A = p1::var1A, var1B = var1A};

as you can't really have an enum as an underlying type of another enum.

More on the subject in this SO post:

Why can't I have an enum as the underlying type of another enum?

Ron
  • 14,674
  • 4
  • 34
  • 47
1

Just because something has a name, doesn't mean it's an lvalue. It's more complicated that than. For example, types have names and they're not values at all! You're probably thinking of expressions that use the name of a variable, which do tend to be lvalues. But an enumerator is not a variable.

Enumerators are not only constants, but they are also prvalues, so not only is the error message correct but it is also worded properly.

You can read about value categories on cppreference.com.

If your book said that var2A=var2B is valid, you would need a new book, because that is nonsense. But the quoted passage does not support your assertion. It's saying that you can create a fresh sign and initialise it from any of those enumerations, like sign mySign = var2A;.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
0

When you do

enum sign{alpha,beta};

It's almost exactly equivalent to

#define alpha 0
#define beta 1

alpha and beta will be equivalent to 0 and 1 respectively, and just like C/C++ don't allow you to assign into 0 or 1, so will the enumerator constants be unassignable.

(In addition to the integer constants, enum sign{alpha,beta} also additionally creates an integer type called enum sign, whose values a debugger may print as alpha and beta instead of just 0 and 1, plus enumerator constants respect scoping and and #defines don't, but otherwise int #defines and enumerator constants are basically interchangable.)

Petr Skocik
  • 58,047
  • 6
  • 95
  • 142
  • It's almost not equivalent to that at all – Lightness Races in Orbit Jan 06 '19 at 16:21
  • @LightnessRacesinOrbit How do you figure? After preprocessing and without using a debugger, I don't think you can distinguish `alpha` and `beta` from `0` and `1` in C. – Petr Skocik Jan 06 '19 at 16:41
  • They're totally different things. One is a name in a scope with a type; the other, after preprocessing, is an integer literal. And just because something is a constant prvalue doesn't mean it's a literal (though non-string literals are constant prvalues). (This is particularly clear with scoped enums.) Sure, you can write a program for which the difference is not observable after compilation but that's true for loads of things. – Lightness Races in Orbit Jan 06 '19 at 16:42
  • @LightnessRacesinOrbit Apart from scoping, I don't think you can (at least for plain old C enumerator constants) observe the difference even during compilation post-preprocessing. That in my book makes them almost equivalent (or at least not "almost not equivalent at all"). – Petr Skocik Jan 06 '19 at 16:50
  • http://coliru.stacked-crooked.com/a/a6bb111b64dda208 Constants and macros are fundamentally different things. – Lightness Races in Orbit Jan 06 '19 at 17:17
  • @LightnessRacesinOrbit Which is why I keep saying after/post preprocessing. – Petr Skocik Jan 06 '19 at 17:20
  • But the problem I demonstrated _is_ visible post-preprocessing. It's the compiler that rejects the code, because the preprocessed program contains a call to a non-existent function. If your argument is "there are no differences other than the differences" then I do agree! – Lightness Races in Orbit Jan 06 '19 at 17:23
  • Pedanticism about reproducing edge cases aside, we have a hard enough time as it is teaching people the differences between constants and preprocessor macros, and I think it's important not to further blur that line when we don't need to. A enumerator and a preprocessor definition are just fundamentally different things, living in different categories of things, and I don't see a reason to lie about that! – Lightness Races in Orbit Jan 06 '19 at 17:25