tags:

views:

170

answers:

4

I've a class and an enum value which have the same name. Inside the class I want to use the enum which gives an error. Is there any way to use the enum without renaming or moving to a different namespace?

Example:

namespace foo {
    enum bar {
        BAD
    };

    class BAD {
        void worse () {
            bar b = BAD; // error
        }
    };
};
A: 

No, there is no way to do that. You should use valid identifier. Valid identifier means that you have to be able to identify with it. :)

anthares
+5  A: 
 bar b = foo::BAD;

or if you are in the global namespace

 bar b = ::BAD;

but that name overloading is not something I'd recommend. C++0X will allow

 bar b = bar::BAD;

which is a better solution if the dependency on C++0X is acceptable.

As promised, the explanation

9.1/2

If a class name is declared in a scope where an object, function, or enumerator of the same name is also declared, then both declarations are in scope, the class can be referred to only using an elaborated-type-specifier (3.4.4)

The elaborated-type-specifier is the form

class BAD b;

This is for compatibility with C where tag names are in a different name space and must be [i]typedef[/i]ed if one want to use them without an elaborated-type-specifier. (A well known example with a function is the struct stat and the function stat in Unix).

That explain why the overloading of a name to designate a class and an enumerator is possible. The reason for which BAD designate the class here is that the name of the class is also defined into the class scope and in a member function definition the scope searched are in order: - the member function scope - the class scope - the namespace containing the class definition

BAD is found at class scope, so the namespace foo is never searched.

AProgrammer
Someone wanted to know if I tried it. I did with 3 different compilers, including como. The rules are arcane, if I remember when I've time, I'll give a fuller explanation with references.
AProgrammer
++, you're right about this
Eli Bendersky
A: 

This works in VS2008, but gives a warning:

bar b = bar::BAD;

Its not something I can recommend.

You should put the enum within another namespace inside foo and qualify both bar and BAD with the new namespace.

quamrana
That's C++0X syntax and it's the preferred solution if available. My solution is C++03 syntax (but use arcane rules).
AProgrammer
+3  A: 

This is one of those tricky parts of how the name lookup is performed.

There are two identifier scopes in C++, one for class types and general identifier scope. The enum value BAD resides in the general identifier scope, while the class type BAR resides in the class identifier scope. That is the reason why you are allowed to have both an enum value and a class with the same name: both names do not collide.

Within class BAD, the identifier lookup rules will find the class BAD before it finds the enum, and thus the error. Now, if you fully qualify the identifier then the name lookup will first check the global identifier scope and match the enum value. On the opposite end, you will have to add the struct or class keyword to declare variables of type BAD.

namespace foo {
   enum bad { BAD; };
   class BAD {
      void worse() { bad b = ::foo::BAD; } // fully qualified will match the enum
   };
}
int main() {
   // foo::BAD b;    // error, foo::BAD is an enum, not a type
   class foo::BAD b; // correct
}

Now, I would advice against this usage. It is generally not a good idea to reuse an identifier like this. Code will be more complex, and probably misleading for the casual reader (the same unqualified identifier refers to different things when used in different contexts). If the names do need to be BAD, consider using an enclosing namespace or class for either the class or the enum (prefer the enum there).

David Rodríguez - dribeas