Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Enum value collision with enum name

Tags:

c++

enums

gcc

Let's take a code construction that I've recently found somewhere in project:

namespace Test
{
    enum EName
    {
        CoolEnum,
        NiceEnum
    };

    enum CoolEnum
    {
        CoolVal1,
        CoolVal2
    };

    enum NiceEnum
    {
        NiceVal1,
        NiceVal2
    };
}

My question is why the compiler allows something like this. Let's take a code sample here:

Test::CoolEnum cEnum = Test::NiceVal1; // INVALID, as compiler refers to Test::CoolEnum value of Test::Ename enum

Why is such confusion allowed? I understand why I have to prepend enum keyword, so the compiler clearly knows that I'm declaring a variable of given enum, not using value of other enum in the same namespace. I just don't understand why in the first place it's even possible to make such a construction.

like image 847
Kamil Klimek Avatar asked Jul 06 '12 14:07

Kamil Klimek


2 Answers

C++11's enum classes are the solution for this:

namespace Test
{
    enum class EName
    {
        CoolEnum,
        NiceEnum
    };

    enum class CoolEnum
    {
        NiceVal1,
        NiceVal2
    };

    enum class NiceEnum
    {
        NiceVal1,
        NiceVal2
    };
}

Then you can use the appropiate NiceVal1:

Test::CoolEnum cEnum = Test::CoolEnum::NiceVal1;

Plain enums were inherited from C, where there is no notion of what a namespace is. If plain enums introduced some kind of namespace, C code which uses enums would not compile at all. That's why enum classes were introduced, in order not to break backward compatibility.

like image 84
mfontanini Avatar answered Nov 01 '22 05:11

mfontanini


The answer is because the standard dictates this behavior. See 3.3.7/2:

A class name (9.1) or enumeration name (7.2) can be hidden by the name of an object, function, or enumerator declared in the same scope. If a class or enumeration name and an object, function, or enumerator are declared in the same scope (in any order) with the same name, the class or enumeration name is hidden wherever the object, function, or enumerator name is visible.

Presumably this is to facilitate compatibility with C's mechanism (where an enumerator doesn't open a new scope) which has been established for a long time.

In your case, at least with g++ you can use typename to indicate you want to use the type instead of the enumerator (typename Test::CoolEnum cEnum = Test::NiceVal1;).

In general however I like to scope all enumerations in a separate namespace or class to prevent these collisions completely.

like image 40
Mark B Avatar answered Nov 01 '22 06:11

Mark B