I just read some code similar to next one:
enum
{
width = 123,
height = 321,
position_x = 234
position_y = 432
};
...
Widget* w = CreateWidget(position_x, position_y, width, height);
Is there any reason to use enum in this case instead of macros or const values?
EDIT: Is it correct to use enum like this? Is this usage considered some kind of abuse in enum usage?
There are plenty of reasons not to use macros. The enum in the question is scoped and won't interfere with the same identifier used in different scopes, so you can for example, defined a member position_x in a class without the macro mangling your class definition.
Comparing the enum to a constant, there are people that prefer the enum as it is guaranteed that it will not add to the binary size of the executable. In the case of a constant, it may add (a bit, well, actually an int) to the size of the binary.
No, there's no special reason to choose an enum over macros or const int values in this case.
Editorial note: It's certainly legal code to use enum in this fashion, but it is a bit strange looking at first glance.
In this particular case, there doesn't appear to be any real deciding factor when choosing between an enum and constant values. Both are better than a macro however, and macros should be avoided in general.
More generally, there are some differentiating aspects between an enum and constants:
enums are distinct types, which is more expressive than integral values
you can take the address of a constant, but you can't take the address of an enum value
It may be more convenient to use enum than static const int as a class member.
class A
{
static const int Foo = 42;
// may have to define A::Foo somewhere
};
class B
{
enum { Foo = 42 };
// done
};
Related
I need to use scoped enums so that I can pass them as specific types to our serialiser. I have given explicit integer values for the enum members of Enum1.
I have put two scoped enums matching the description above into a bitfield thus
enum class Enum1 {
value1 = 0x0,
value2 = 0x1,
value3 = 0x2
};
enum class Enum2 {
value1 = 0x0,
value2,
value3,
// ...
value14
};
struct Example {
Enum1 value1 : 2;
Enum2 value2 : 6;
}
Now wherever I use the Example type, I get the warning "'Example::value1' is too small to hold all values of 'Enum1'", and similarly for Enum2. Note that this is not the case for the values we have defined and we are not concerned at all with values outside of these.
This is quite a serious distraction in our build process - the project is large and complex and we don't want to have to scan through many of these warnings (and there are many).
I had a look for a GCC (G++) flag to disable the specific warning. Is there one that I can pass on the command line? Ideally, I would use the warning pragma to disable it locally, if possible.
There is little scope for changing the code structure at this point, but we could really use these spurious warnings removed.
Edit: Added scoped enums with identifiers changed.
The problem is that an scoped enum always has an integral underlying type. By default, it is int but you can change it to any other integral type, such as unsigned char.
Unfortunately you cannot change the underlying type to a bit-field, as they are not real C++ types.
You could try disabling the warning, but a quick skim through the G++ code reveals these lines (gcc/cp/class.c:3468):
else if (TREE_CODE (type) == ENUMERAL_TYPE
&& (0 > (compare_tree_int
(w, TYPE_PRECISION (ENUM_UNDERLYING_TYPE (type))))))
warning_at (DECL_SOURCE_LOCATION (field), 0,
"%qD is too small to hold all values of %q#T",
field, type);
The key here is the call to warning_at(...) instead of warning(OPT_to_disable_the_warning, ...). So currently there is no option to disable it. Except recompiling the compiler yourself!
For what it is worth CLang++-3.7.1 does not warn about it.
As I recall, an enum with a declared underlying type can hold any value of that type, regardless of what enumeration constants are defined. Since you can say
val= enum2{148}
and expect it to work properly, the warning seems correct for that case. You are not declaring a base type, and historically this means that the enum is only guaranteed to be big enough to hold the range of values given by the lowest through highest enumeration constant. So I would expect no warning here. Maybe the new enum class also expects a full range even though the underlying type was automatically determined (or the compiler thinks it does)? You might try using a pure old-syntax enum and see if that works any differently.
Emitting this warning is a bug, because all declared enumerator (values) in fact can be held by the bitfield fields.
Like with traditional enums, a variable of scoped enum type still can hold any value of its underlying type, even ones that don't correspond to a declared enumerator.
However, warning about this like this
warning: 'some bitfield field' is too small to hold all values of 'enum class FOO'
is quite pointless because assigning a too large value as in
Example x;
x.value1 = Enum1(8);
already generates a -Woverflow warning.
Consequently, GCC fixed this warning in version 9.3.
FWIW, Clang never warned about.
IOW, to suppress this warning in GCC you have to upgrade to GCC version 9.3 or later.
For other people like me who end up here from search:
This problem only applies to C++11 scoped enums. If you need bitfield enums, old style enums without explicit storage size work fine:
enum Enum1 {
Enum1_value1 = 0x0,
Enum1_value2 = 0x1,
Enum1_value3 = 0x2
};
enum Enum2 {
Enum2_value1 = 0x0,
Enum2_value2,
Enum2_value3,
// ...
Enum2_value14
};
struct Example {
Enum1 value1 : 2;
Enum2 value2 : 6;
}
The code below prints unsigned int as the underlying type of all the constants inside the enum Test
#include <iostream>
#include <type_traits>
#include <typeinfo>
#include <cxxabi.h>
struct Test
{
enum { a = true, b = 1 };
};
static_assert(std::is_same<
std::underlying_type_t<decltype(Test::a)>,
std::underlying_type_t<decltype(Test::b)>>::value, ""
);
int main()
{
int status;
auto const& bi = typeid(std::underlying_type_t<decltype(Test::a)>);
std::cout << abi::__cxa_demangle(bi.name(), 0, 0, &status); // unsigned int
}
Live Example. This also happens if Test contains two separate enums with a and b as before.
Question: is it possible to detect that Test::a is initialized with bool and Test::b with int? Is there any experimental code for this in any of the Reflection Study Group proposals for C++17?
NOTE: I know I can work around it by replacing Test with
struct Test
{
static constexpr auto a = true;
static constexpr auto b = 1;
};
but I find the enum version slightly less verbose in its usage.
It is not possible and I consider it very unlikely that it will ever be possible.
The reason is that a and b are values of the (in your case unnnamed) enum. Thus they are, by definition, of the type of the enum, meaning: Of the same type. The expressions used to initialize them and their respective types are only used to "calculate" the underlying type of the enum, not of any individual values.
Considering this fact, I think that even reflection will not help to recover the information as the type of the initializing expression is abstracted away when you look at an enum's value.
What you'd need is an even deeper level of inspection where you'd need to access the expression used to initialize the values. That would mean that compilers will have to store a lot of additional information for every variable, values, etc. (since this would be a general thing not just for enums).
Consider what that means:
Increased compile times
Increased memory usage when compiling
Every value would effectively now have two types, the type it is declared as and the type of the expression it was initialized from
The last point is what I would consider the real catastrophe for the language. A value should have a single type, the expression used to initialized the value should not be accessible in any way. This is what abstraction is about, breaking it could lead to all kinds of subtle dependencies and a lot of complexity.
Disclaimer: This is just my personal opinion, I can't speak for anyone on the committee or in the working groups.
You could differentiate int enum values from non-ints as following:
struct Test
{
enum : short { a = true };
enum : int { b = 1 };
// enum : bool { c = false };
};
Unfortunately, VC2010 fails to compile a bool as underlying type, which is probably not considered as an integral type. This might not be an issue if your use case only requires separating ints from non-ints.
I'm a newbie to C++ and especially C++11, so since I've now got to use it, a few questions about 'enum' and 'enum class' came up:
Can I assign values after the enumeration has been declared?
enum MyEnum;
MyEnum::HELLO = 0;
MyEnum::WORLD = 1;
Can I assign values to a number? (ex.: Myenum::0 = 2)
enum MyEnum;
MyEnum::0 = 16;
MyEnum::1 = 24;
MyEnum::3 = 64;
How does enum class work when using a struct or class as the underlying type?
Would the entries in the enumeration be valid instances of the struct/class?
class Test {
private int v = 0;
Test(int v) {
this->v = v;
}
};
enum class MyEnum : Test {
Test0 = new Test(0),
Test1 = new Test(1),
};
I found these links when I searched for the topic:
http://www.stroustrup.com/C++11FAQ.html#enum
Do we really need "enum class" in C++11?
C++11 enum class instantiation
Which, as you can see, left a few questions.
No. You cannot do any of those.
However, you may provide the definition the enum after its declaration as:
enum MyEnum; //declaration
enum MyEnum //definition
{
HELLO = 0,
WORLD = 1;
};
Can I assign values to a number?
No. That doesn't make sense. A number already has a value. It is constant.
Please get an introductory book on programming in C++. Here are few recommendations :
The Definitive C++ Book Guide and List
First of all, you cannot ever assign to a value in C++. The following is illegal:
42 = 23;
And for pretty much the same reason you cannot assign the value of an enum either.
Furthermore, you cannot even use the values of an enum after its declaration (i.e. you cannot write auto x = enum_name::name;), only after definition. You can only use the enum’s name.
Can I assign values to a number?
I’m not sure what this is supposed to mean but apart from what I’ve said before that syntax is illegal anyway. That is, you cannot access the second enum value by writing enum_name::1.
How does enum class work when using a struct or class as the underlying type?
You cannot use custom types as underlying types, only built-in integral types.
Example:
enum SomeEnum
{
DD,
PP,
NN
};
void someFunc(int a)
{
}
int main()
{
SomeEnum e = DD;
someFunc(a) // calls someFunc with value 0
return 0;
}
This works in MSVC but is it non standard?
Thanks
An enum has an underlying integer type (the type used to store the value of the enum), and the enum value can be implicitly converted to that integer type's value.
In your case the underlying type is int, and the value is 0. Everything is okay.
The identifiers in an enumerator list are declared as constants that have type int and may appear wherever such are permitted.
6.7.2.2 here http://www.open-std.org/JTC1/SC22/WG14/www/docs/n1256.pdf
It's absolutely valid because, as GManNickG and tomato said, all enums are of type int (in fact, in C, enums ARE ints and you can assign them values outside the scope of the enum.
typedef enum _foo
{
val1 = 57
} foo;
...
foo f = 99; // compiles in C but not C++
In fact, most compilers won't complain if the function argument type was bool or float or some other primitive number type because enums act as constant integer values like 0, -1, 200, etc...
What I'd say though, is that, if you have control over someFunc's signature and you want to ensure in C++ that no invalid values are passed in, change it to be
void someFunc(SomeEnum a);
for more typesafety
Also, always initialize your first enum value at least. I may be wrong on this but, back in the day, the compiler was allowed to pick an arbitrary starting value for your enum. Most of the time it picked 0 but not always. Even if that's not the case, it makes the code a little more self documenting and obvious.
The typical way to define an integer constant to use inside a function is:
const int NumbeOfElements = 10;
the same for using within a class:
class Class {
...
static const int NumberOfElements = 10;
};
It can then be used as a fixed-size array bound which means it is known at compile time.
Long ago compilers didn't support the latter syntax and that's why enums were used:
enum NumberOfElementsEnum { NumberOfElements = 10; }
Now with almost every widely used compiler supporting both the in-function const int and the in-class static const int syntax is there any reason to use the enum for this purpose?
The reason is mainly brevity. First of all, an enum can be anonymous:
class foo {
enum { bar = 1 };
};
This effectively introduces bar as an integral constant. Note that the above is shorter than static const int.
Also, no-one could possibly write &bar if it's an enum member. If you do this:
class foo {
static const int bar = 1;
}
and then the client of your class does this:
printf("%p", &foo::bar);
then he will get a compile-time linker error that foo::bar is not defined (because, well, as an lvalue, it's not). In practice, with the Standard as it currently stands, anywhere bar is used where an integral constant expression is not required (i.e. where it is merely allowed), it requires an out-of-class definition of foo::bar. The places where such an expression is required are: enum initializers, case labels, array size in types (excepting new[]), and template arguments of integral types. Thus, using bar anywhere else technically requires a definition. See C++ Core Language Active Issue 712 for more info - there are no proposed resolutions as of yet.
In practice, most compilers these days are more lenient about this, and will let you get away with most "common sense" uses of static const int variables without requiring a definition. However, the corner cases may differ, however, so many consider it to be better to just use anonymous enum, for which everything is crystal clear, and there's no ambiguity at all.
Defining static constants directly in the class definition is a later addition to C++ and many still stick to the older workaround of using an enum for that. There might even be a few older compilers still in use which don't support static constants directly defined in class definitions.
Use of enum have one advantage. An enum type is a type, so if you define, for example:
enum EnumType { EnumValue1 = 10, EnumValue2 = 20 ... };
and you have a function like:
void Function1(EnumType Value)
the compiler checks that you are passing a member of the enum EnumType to the function, so only valid values for parameter Value would be EnumValue1 and EnumValue2. If you use constants and change the function to
void Function1(int Value)
the compiler checks that you are passing an int (any int, a constant, variable or literal) to the function.
Enum types are good for grouping related const-values. For only one const value, I do not see any advantage.
In your case, I'd use a constant as well. However, there are other cases where I might be adding other, related constants. Like this:
const int TextFile = 1; // XXX Maybe add other constants for binary files etc.?
In such cases, I use an enum right away with a single value, like this:
enum FileType {
TextFile = 1
// XXX Maybe add other values for binary files etc.?
}
The reason is that the compiler can then issue warnings when I'm using the constant value in switch expressions, as in:
FileType type;
// ...
switch ( type ) {
case TextFile:
// ...
}
In case I decide to add another constant value which is related to the existing value (a different type of file, in this example), virtually all compilers will issue a warning since the new value is not handled in the switch statement.
If I had used 'int' and constants instead, the compiler wouldn't have a chance to issue warnings.
The only reason for using the "enum hack" is that old compilers do not support in-class const definitions, as you say in your question. So, unless you suspect that your code will be ported to an old compiler, you should use const where const is due.
I think that there's no reason to use an enum, and that it's actually better to use a static const int for this purpose, since an enum has its own type (even if implicitly convertible to an integer).
There is a difference between those two. Enums don't have an adress as far as I know. static const ints do though. So if someone takes the adress of the const static int, casts away the const, he can modify the value (although the compiler might ignore the change because he thinks it's const). This is of course pure evil and you should not do it - but the compiler can't prevent it. This can't happen with enums.
And of course - if you (for some reason) need the adress of that const, you need the static const int.
In short - enum is an rvalue while const static int is an lvalue. See http://www.embedded.com/story/OEG20011129S0065 for more details.
Well, the portability is a good reason for using enum. It is great, because you don't have to worry whether your compiler supports "static const int S = 10" or not...
Also, as far as I remember, static variable must be defined somewhere, as well as declared, and the enum value must be declared only.
bottom line - use const.
more details:
I'm not a c++ expert, but this seems a more general design question.
If it's not a must, and you think there's a very low/non-existent probability that the enum will grow to have more then one value, then use a regular const.
even if you are wrong and at some point in the future there will be more values, making an enum the right choice - a simple refactoring and you change you const to enum.