5

when I run the below code - I'm getting the warning "narrowing conversion from int to long unsigned int inside {} is ill-formed in C++11 [-Wnarrowing]. I'm using GNU 4.8 compiler.

typedef struct TableEntry
{
    unsigned long value;
    const char *label;
} TableEntry;

enum FunctionType
{
    NORMAL   = 0, 
    RANGE    = 1
};


TableEntry functionTypes[] = 
{
    {NORMAL,   "NORMAL"},
    {RANGE, "RANGE"}
};

I don't understand why compiler is considering enum as an int?
Is this a bug in GCC 4.8? Is there any workaround? Any help is appreciated.

Wild Widow
  • 2,359
  • 3
  • 22
  • 34
  • 2
    I believe enums are always considered `int`s behind-the-scenes. If you don't specify the values of your enum values, they default to 0, 1, 2, ... In this case you should be okay with the implicit conversion, though, since the conversion shouldn't cost you any accuracy. – cf- Feb 11 '14 at 23:51
  • 1
    We have these warnings in every file. about 150 files . My boss doesn't like to see the warnings. – Wild Widow Feb 11 '14 at 23:55
  • 1
    This is valid C++03 code so g++'s warning is most likely unfounded. It would be noteworthy indeed if the C++11 standard broke C++03 code wholesale. That said, this is just another reason for not using unsigned integers for *number* values. – Cheers and hth. - Alf Feb 11 '14 at 23:59
  • 1
    As long as you're certain the implicit conversion won't cause you any problems, you _could_ temporarily disable the warning. But I really don't suggest that for a long-term solution, since having that warning enabled might save you headaches in other data-conversion scenarios. – cf- Feb 11 '14 at 23:59
  • 1
    enum FunctionType : unsigned long { /* etc */ }; This is doing it backwards, do fix the struct declaration instead. – Hans Passant Feb 12 '14 at 00:00

4 Answers4

7

If practical do:

enum FunctionType
{
    NORMAL   = 0, 
    RANGE    = 1
};

typedef struct TableEntry
{
    FunctionType value;
    const char *label;
} TableEntry;


TableEntry functionTypes[] = 
{
    {NORMAL,   "NORMAL"},
    {RANGE, "RANGE"}
};

Otherwise, change the type in the struct to int, or explicitly base the enumeration on the same type as in the struct.

Btw., I the think g++ warning is unfounded and wrong, since the original code is valid C++03. Correction: As I understand it now, the diagnostic is correct, and this is a breaking change in C++11. I just couldn't believe it.


About the naming convention: those all uppercase identifiers are good for Java programmers (who are used to that convention), but in C++ they increase the chances of inadvertent text substitution. There are also the aesthetic considerations. Much win in reserving all uppercase for macros.

Cheers and hth. - Alf
  • 142,714
  • 15
  • 209
  • 331
  • Can you point to the source for the information that this is a breaking change in c++11? – Dave Apr 21 '16 at 13:00
  • @Dave: The code in the question is one example. It's fine as C++03, invalid as C++11. That's what “breaking” means, that it breaks existing code. – Cheers and hth. - Alf Apr 21 '16 at 13:13
4

Usually underlying type of unscoped enumerations is int ( it can be any integral type that can represent all values of enumerators).

However I do not see any narrowing conversion because type unsigned long can represent all values of type int.

EDIT: It seems I am wrong because I found an example in the Standard that contradicts my assumption

unsigned int ui1 = {-1}; // error: narrows

So unsigned int can not be initialized by using an initializer list that contains a negative number.

So to avoid the warning the enumeration could be written as

enum FunctionType : unsigned int // or unsigned long
{
    NORMAL   = 0, 
    RANGE    = 1
};
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
2
  • you could change "value" to int
  • or you could use the new "enum class" (c++11) which is strongly typed, and declare your "value" as this type.
Syl
  • 2,733
  • 2
  • 17
  • 20
  • Appreciate your suggestion. I got these warnings in about 150 files.Is there a better way to do this ? – Wild Widow Feb 11 '14 at 23:56
  • 1
    Interesting, my first two recommendations would have been: change the type of `value` to a `FunctionType`, or make `FunctionType` backed by `unsigned long`. – Mooing Duck Feb 11 '14 at 23:58
1

Since you're using c++11, you could declare your enum like so:
enum Enum2 : unsigned char;
That should force the enum to work. That said, IDEONE has no warnings/errors for your posted code. Could just be GCC being overly pedantic.

KitsuneYMG
  • 12,753
  • 4
  • 37
  • 58