C++ doubly enum value assignment - c++

In an open source code I found an enum initialization that looked like that:
enum example {
FIRST,
FIRST_AGAIN = FIRST,
SECOND,
ETC
};
I was surprised how the values of the enum are going to be initialized, because the FIRST_AGAIN would get the value 0 because FIRST is 0, too. But i thought it could affect the FIRST value to be -1, when the FIRST_AGAIN value is 0.
So I looked with the debugger what values are assigned to the key words. FIRST and FIRST_AGAIN are assigned with 0.
So, my question is, is it really allowed (GCC compiles it, but what does the C++ standard say?) to assign two key words in an enumaration with the same value? And how does the compiler translate the assignment? Because to know the value of FIRST, the compiler should gone through the whole enum first and look if any key word is assigned, back from there, he could assign all the other values, but he doesn't know what the assignment FIRST_AGAIN = FIRST means.
Maybe the question is stupid and it's common use to do something like that. What would be the benefits of assigning two key words with the same value?

So, my question is, is it really allowed (GCC compiles it, but what does the C++ standard say?) to assign two key words in an enumaration with the same value?
That's fine. The C++ standard doesn't say anything about it in the normative text, so it's implicitly allowed, but does include an example:
enum { a, b, c=0 };
Which defines a and c as zero.
And how does the compiler translate the assignment? Because to know the value of FIRST, the compiler should gone through the whole enum first
No, the compiler doesn't need to do that. An enumerator definition without an explicit value doesn't depend on later enumerator definitions. Its value is the value of the previous enumerator plus one, or zero if there were no previous enumerators.
Maybe the question is stupid and it's common use to do something like that. What would be the benefits of assigning two key words with the same value?
One possibility:
enum E {
A = 20,
B = 30,
C = 40,
MIN = A,
MAX = C
}
Here, it may be expected that the values of MIN and MAX may change as enumerators are added or removed, but the values of A, B and C are expected to remain constant. By using C where C is wanted, and MIN and MAX where a range is wanted, code may be future-proof for later versions of whatever library defines this enumeration.

Related

Can we define an enum variable like an array? [duplicate]

This question already has answers here:
How to cast int to enum in C++?
(6 answers)
Closed last year.
i have below enum :
enum words= {dog, cat, horse, hen, goat, pig, sheep};
can i assign a new enum constant as below :
words word = words[4];
What i want to do is get a random number between 0 and words.size() .and i want to pick that word from the enum . is it possible?
int wordno = (rand()%8);
words word = (words)wordno;
Your enum declaration is a bit wrong. It should be
enum words {dog, cat, horse, hen, goat, pig, sheep};
Since C++11 it is usually also better to use an enum class instead, see this question for details:
enum class words {dog, cat, horse, hen, goat, pig, sheep};
Note that enum enumerators already have a numeric value. If you don't specify these numeric values manually, they are from left-to-right starting from zero increasing by one. So e.g. horse has the numeric value 2 in your enumeration.
However, it is not directly allowed to convert between the numeric value and the enumeration implicitly. If you need to do that, you must use static_cast:
auto word = static_cast<words>(wordno);
When doing this, you need to be careful however (which is also why the explicit cast is required), because you are not allowed to cast an integer value that is outside the range of numeric values of the enumeration in this way. In your code you do rand()%8 which can return values up to 7, but the largest numeric value in your enumeration is 6 for sheep. You would have undefined behavior with that.
auto can be replaced by words. It just lets the compiler figure out the correct type, so I don't have to write it twice. (It is already in the static_cast.)
As a sidenote, rand is not a good random number generator for many reasons (see e.g. this question). Since C++11 you can use the more modern <random> library, see this question.
Also as a sidenote I suggest avoiding C-style casts such as (words)wordno. Instead use static_cast as I showed above. You are much less likely to make serious mistakes this way, since the C-style casts are usually too permissive in what casts they allow.
For words word = words[4];, this syntax does not work. But it is not really necessary, since as above, you can initialize word directly with the value 4 with an explicit cast.
auto word = static_cast<words>(4);
But if you are intending to assign a constant value, you should just use the enumerator directly. That is what they are for:
auto word = words::goat;

Validate function parameters based on given constraints

Before saying anything, please let me make it clear that this question is NOT language-specific but part of my work on an interpreter.
Let's say we have an enum of Value types. So a value can be:
SV, // stringValue
IV, // integerValue
AV, // arrayValue
etc, etc
then let's say we have a function F which takes one of the following combinations of arguments:
[
[SV],
[SV,IV],
[AV]
]
Now, the function is called, we calculate the values passed, and get their types. Let's say we get [XV,YV].
The question is:
What is the most efficient way to check if the passed values are allowed?
(The original interpreter is written in Nim, so one could say we could lookup the value array in the array of accepted value arrays like: accepted.contains(passed) - but this is not efficient)
P.S. ^ That's how I'm currently doing it, although I've explored the option of using bitmasks too. However, I cannot seem how it would help, since order plays an important part too.

Confusion between constants and literals?

I am currently reading about constants on the c++ tutorial from TutorialsPoint and, where it says:
Constants refer to fixed values that the program may not alter and they are called literals.
(Source)
I do not really get this. If constants are called literals and literals are data represented directly in the code, how can constants be considered as literals? I mean variables preceded with the const keyword are constants, but they are not literals, so how can you say that constants are literals?
Here:
const int MEANING = 42;
the value MEANING is a constant, 42 is a literal. There is no real relationship between the two terms, as can be seen here:
int n = 42;
where n is not a constant, but 42 is still a literal.
The major difference is that a constant may have an address in memory (if you write some code that needs such an address), whereas a literal never has an address.
I disagree with the claim "...There wasn't a thing called const in C originally so this was fine." const is actually one of the 32 C keywords. Google to see.
With that rested, I think the man missed something at TP. To be fair to them at Tutorials Point, they had an article that explained the difference thus (full quote, verbatim):
https://www.tutorialspoint.com/questions/category/Cplusplus
A literal is a value that is expressed as itself. For example, the number 25 or the string "Hello World" are both literals.
A constant is a data type that substitutes a literal. Constants are used when a specific, unchanging value is used various times during the program. For example, if you have a constant named PI that you'll be using at various places in your program to find the area, circumference, etc of a circle, this is a constant as you'll be reusing its value. But when you'll be declaring it as:
const float PI = 3.141;
The 3.141 is a literal that you're using. It doesn't have any memory address of its own and just sits in the source code.
Pls don't disparage those fellows doing what you call "random tutorials". Kids from poorer homes and less developed world can't afford your " good C++ textbooks " e.g. Scott Myers Effective C++ It is these online free tutorials they can have, and most of these tutorials do better explaining than the "good books".
By any means read them guys. Get confused some then come over here to StackOveflow or Quora to have your confusion cleared. Happy coding guys.
The author of the article is confused, and spreading that confusion to others (including you).
In C, literals are "constants". There wasn't a thing called const in C originally so this was fine.
C++ is a different language. In C++, literals are called "literals", and "constant" has a few meanings but generally is a const thing. The two concepts are different (although both kinds of things cannot be mutated after initial creation). We also have compile-time constants via constexpr which is yet another thing.
In general, read a good book rather than random tutorials written by randomers on the internet!
While the first part of the statement makes sense
Constants refer to fixed values that the program may not alter
the continuation
and they are called literals
is not really true.
Neil has already explained the semantical difference between the literal and the constant in his answer. But I would also like to add that the values of constant variables in C++ are not necessarily known at compile time.
// x might be obtained at runtime
// for instance, from the user input
void print_square(int x)
{
const int square = x*x;
std::cout << square << '\n';
}
Literals are values that are known at compile-time, which allows the compiler to put them to a separate read-only address space in the resulting binaries.
You can also enforce your variables to be known at compile-time by applying constexpr keyword (C++11).
constexpr int meaning = 42;
P.S. And I also do agree with a comment suggesting to use a good book instead of tutorialspoint.
If constants are called literals and literals are data represented directly in the code, how can constants be considered as literals?
The article from which you drew the quote is defining the word "constant" to be a synonym of "literal". The latter is the C++ standard's term for what it is describing. The former is what the C standard uses for the same concept.
I mean variables preceded with the const keyword are constants, but they are not literals, so how can you say that constants are literals?
And there you are providing an alternative definition for the term "constant", which, you are right, is inconsistent with the other. That's all. TP is using a different definition of the term than the one you are used to.
In truth, although the noun usage of "constant" appears in a couple of places in the C++ standard outside the defined term "null pointer constant", apparently with the meaning you propose here, I do not find an actual definition of that term, and especially not one matching yours. In truth, your definition is less plausible than TutorialPoint's, because an expression having const-qualified type can nevertheless designate an object that is modifiable (via a different expression).
Constant is simply a variable declared constant by keyword 'const' whose value after being declared shouldn't be altered during the course of the program (and if tried to alter it will result in an error).
On the other hand, literal is simply what is used and represented as it is typed in. For example, 25 when used in an expression (x+4*y+25) will be termed as literal.
Whenever we use String values or directly supply it in double quotes ("hello"), then that value in double quotes is called literal.
For example, printf("This is literal");
And if you are assigning a string value to a variable then thereafter you will refer to the variable (which could be declared constant if desired) and not exclusively to the value you have stored in it, i.e., only till the point you are supplying a value (string type of any other type) to the variable, the value is referred to as literal value, after that the variable is talked about whenever referring that value.
Once again, the value(25) in expression : x+4*y+25 is literal.
The value(4) in the term 4*y is also a literal (since it is exactly as we see it and is known to compiler beforehand).
--> The value(4) in the term 4*y is called numerical coefficient in algebraic terms and y is called literal coefficient in algebraic terms.
Hence,
All the above explanation I have given is in computer terms only. The meaning of literals and constants in Algebra are somewhat different than used in computer terms.
"Constants refer to fixed values that the program may not alter and they are called literals. (Source)"
The sentence construction is weird which is leading to the confusion.
Here, the the "they" that are referring to are the the fixed values and not constants. I would phrase it as "Constants refer to fixed values, that the program may not alter, called literals." which is less confusing I hope.
Constants are variables that can't vary, whereas Literals are literally numbers/letters that indicate the value of a variable or constant.
I can explain it this way.
Basically, constants are variables whose value cannot change.
Literals are notations that represent fixed values. These values can be Strings numbers etc
Literals can be assigned to variables
Code :
var a = 10;
var name = "Simba";
const pi = 3.14;
Here a and name are variables. pi is a constant. ( Constants are those variables whose value doesn't change. )
Here 10, "Simba" and 3.14 are literals.

Assigning values to enum

While doing a review of some older code, I notice the following two strange constructions using enum (two different files/classes/namespaces, just putting them together here):
enum FirstEnum
{
A_CHOICE
,ANOTHER_CHOICE=1
,YET_SOME_OTHER_CHOICE
};
enum SecondEnum
{
FIRST_CHOICE
,SECOND_CHOICE
,THIRD_CHOICE
,DEFAULT_CHOICE=SECOND_CHOICE
};
I think both constructions are wrong.
The first one assigns a value to one of the choices, but not to the others, meaning that things might go wrong if new choices are added.
In the second case, we end up with two enumeration elements having the same underlying value.
Is there any reason why the C++ standard allows both constructions?
(using Visual Studio 2010)
The first one assigns a value to one of the choices, but not to the others, meaning that things might go wrong if new choices are added.
I don't know what you mean by "go wrong". It's well-defined that if you don't specify a value for an enumerator, its value is one more than the previous (or zero, if it's the first).
In the second case, we end up with two enumeration elements having the same underlying value.
Yes we do. That would be wrong if enumerations were supposed to be a set of unique values but (in C++) they aren't.
Is there any reason why the C++ standard allows both constructions?
Because, in C++, an enumeration is simply a way to declare a set of related, named, constant values. It doesn't try to restrict what values they can take.
This article from Microsoft should help:
http://msdn.microsoft.com/en-us/library/2dzy4k6e(v=VS.80).aspx
The first one assigns a value to one of the choices, but not to the others
By default, the first enumerator has a value of 0, and each successive enumerator is one larger than the value of the previous one, unless you explicitly specify a value for a particular enumerator.
In the second case, we end up with two enumeration elements having the same underlying value.
Enumerators needn't have unique values within an enumeration. The name of each enumerator is treated as a constant and must be unique within the scope where the enum is defined.
The article includes examples of how these features could be taken advantage of.
I don't have a quote from the standard for you, but enums are specified such that uninitialized values take on a value one larger than the value preceding them.
In the FirstEnum, YET_SOME_OTHER_CHOICE would therefore be 2 (ANOTHER_CHOICE+1). It is also perfectly legal to have multiple equivalent values within an enum.
The first one assigns a value to one of the choices, but not to the others, meaning that things might go wrong if new choices are added.
What might go wrong? Sure, if somebody changes the first example to
enum FirstEnum
{
A_CHOICE //0
,A_THIRD_CHOICE //1
,ANOTHER_CHOICE=1 //1
,YET_SOME_OTHER_CHOICE //2
};
Then yes, they will get problems if they didn't expect two values to be the same in the enum. The same if somebody had #defined these values, and accidentally made two of them the same.
And for your second example, the names of the values in the enumeration give a hint as to why that is useful. You can have a default value for variables of type SecondEnum stored in the definition of SecondEnum, allowing you to do things like
SecondEnum var = DEFAULT_CHOICE;
without the need for #defines or constants that are closely coupled to the enum definition but aren't part of it.
Is there any reason why the C++ standard allows both constructions?
I'm not on the standards committee, but if I were to guess, it's because both constructions are useful for programmers.

Declearing enum and setting values manually not in increasing order

Is the definition of enums in C++ and setting values in random order a valid? Is it used in any well-known code?
e.g.:
enum ESampleType{ STPositiveControl='P', STNegativeControl='N', STSample='S' };
VS2008 compiles without warnings. I wonder whether gcc would.
In my opinion, it a least harms "least surprise rule" as iterating over all values using
for(int i=STPositiveControl; i<=STSample; ++i)
would fail.
P.S: The rationale for this approach:
In my DB application I'm defining wrapper methods. Some columns contain "constants" encoded as
single char. I'm trying to make it a little more type safe.
It's a standard and widely used feature. Most of the time (but
not always) it will be used to create bitmaps, but it can also
be used as you show, to give "printable" values to the enum
contants.
It shouldn't surprise anyone who knows C++, as it is widely
used.
Yes it is valid.
There is an example use of it in the book The C++ Programming Language (3rd Edition) by Bjarne Stroustrup, section "6.1 A Desk Calculator [expr.calculator]" (and more precisely "6.1.1 The Parser [expr.parser]"), for the parser code of a simple arithmetic calculator. Here's an excerpt:
The parser uses a function get_token() to get input. The value of the most recent call of get_token() can be found in the global variable curr_tok. The type of curr_tok is the enumeration Token_value:
enum Token_value {
NAME, NUMBER, END,
PLUS='+', MINUS='-', MUL='*', DIV='/',
PRINT=';', ASSIGN='=', LP='(', RP=')'
};
Token_value curr_tok = PRINT;
Representing each token by the integer value of its character is convenient and efficient and can be a help to people using debuggers. This works as long as no character used as input has a value used as an enumerator – and no character set I know of has a printing character with a single-digit integer value. (...)
(That last sentence is specific to this example, because the enumeration mixes "default-value" and "explicit-value" enumerators and wants each one to be unique.)
However it's only an educative example (and notably it uses a global variable, and CAPS names for enumerators when you should reserve them for macros (but Stroustrup doesn't like macros :p)).
Now, indeed you can't iterate over it (at least with a plain for loop; but see this question). (And as James Kanze pointed, an enum's values are not always ordered, contiguous, and unique.)