Search code examples
c++classenumsabstractderived

Enum Members conflict with class names


I recently produced a wierd set of errors when working on a little project. This was basically the code that caused it:

#include <memory>

enum derivedtype {B, C};

//abstract class
class A{};

class B : public A
{};
class C : public A
{};

int main()
{
  {
    std::unique_ptr<A> myb(new B);
    std::unique_ptr<A> myc(new C);
  }
}

Which produces this compiler error:

enumclasserror.cpp: In function ‘int main()’:
  enumclasserror.cpp:15:30: error: ‘B’ does not name a type
  std::unique_ptr<A> myb(new B);
                          ^
  enumclasserror.cpp:16:30: error: ‘C’ does not name a type
  std::unique_ptr<A> myc(new C);

The fix was adding the class keyword after the new:

std::unique_ptr<A> myb(new class B);

Now the enum was included in the headerfile of the abstact class in the original code(which made it even harder to spot), but nevermind that; I could have never imagined that the members of an enum can cause the creation of an instance to fail. It literally took me hours to find that bug. Can anyone explain to me why that happens? Does new make any sense with enums?

P.S.: The error was found by a collegue who uses clang which suggested the class keyword. The standard c++ compiler on my Ubuntu, as you can see, didn't tho..


Solution

  • In your example B from enum hides class B. Section 3.3.10 of the standard describes the rules for name hiding:

    A class name (9.1) or enumeration name (7.2) can be hidden by the name of a variable, data member, function, or enumerator declared in the same scope. If a class or enumeration name and a variable, data member, 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 variable, data member, function, or enumerator name is visible.

    Language designers needed to set precedence rules, so they decided that enum constant name should win. This rule seems arbitrary, and is probably modeled after some old rule in the C standard. However, it is part of the standard, so every compiler must comply with it.

    It goes without saying that making a class name collide with an enum member is a very bad idea. The best solution to this problem is renaming your class.