0

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..

Trevor Hickey
  • 36,288
  • 32
  • 162
  • 271
jaaq
  • 1,188
  • 11
  • 29
  • Just to clarify, saying "bug", and "failed instance creation" sound like runtime problems. The only problems you've experienced are compiler errors-- not bugs. – Trevor Hickey Jun 29 '16 at 23:56
  • @TrevorHickey: Compiler errors are bugs. – Lightness Races in Orbit Jun 29 '16 at 23:58
  • Regarding bugs, Wikipedia defines it as "...an error, flaw, failure or fault in a computer program or system that causes it to produce an incorrect or unexpected result, or to behave in unintended ways." – pingul Jun 30 '16 at 00:02
  • 1
    No computer program faulted. The compiler outputted a message exactly as it was intended to. OPs program never ran at all. To a compiler writer and someone familiar with the language, this is not an unexpected result. If the compiler built the program, that would have been a bug. – Trevor Hickey Jun 30 '16 at 00:06

2 Answers2

5

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.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • Thank you very much! This was exactly the kind of answer I was hoping for ;) As I said before it was not obvious to me that name hiding also aplies in this case, and I haven't ever read about this in any tutorials, since obviously(I see that now) having the same names is indeed a very bad idea. – jaaq Jun 30 '16 at 00:06
  • Name hiding occurs unless there's an exception, not the other way around. If there were an exception here, your code would have worked! This question is so vacuous :) – Lightness Races in Orbit Jun 30 '16 at 00:18
  • Regarding "_This rule seems arbitrary..._", it is actually not at all arbitrary but to support backward compatibility with structs and enums in C. Refer [this](https://stackoverflow.com/questions/57865891/whats-the-struct-hack-and-type-non-type-hiding) answer. – Cheshar Apr 26 '20 at 12:39
2

I'm not sure what else you expected here.

First, you introduced integral constants named B and C. Of course, you cannot new these. That would be like writing new 42.

Then, you introduced types with the same names. Okay, fine, that's allowed, but in order to use these you must now refer to them as class B and class C (or struct B and struct C), as you've discovered.

Do not use the same name for different things.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
  • The OP may have expected non-type names to be ignored in the name lookup occurring in the *type-id* of the *new-expression*. Evidently, that doesn't happen. – Brian Bi Jun 29 '16 at 23:51
  • @Brian: The OP was wrong.. and already has discovered this. Not really seeing a question to answer here to be honest. Deliberately ironic that I answered it anyway, I suppose... – Lightness Races in Orbit Jun 29 '16 at 23:51
  • The question implies this answer. –  Jun 29 '16 at 23:52
  • @DieterLücking: Exactly. What is left? Nothing, as far as I can tell. – Lightness Races in Orbit Jun 29 '16 at 23:52
  • Maybe a "why is the language constructed this way?" question. Well, that's entirely vacuous and does not warrant answering either... – Lightness Races in Orbit Jun 29 '16 at 23:52
  • Well it was just an incredibly stupid error on my side, which made it even harder to spot. Obviously new 42 won't work, but why exactly does the compiler even try to pick the enum when there's also a class declaration with the same name? I don't see a conflict there at all and don't get why this won't compile. – jaaq Jun 29 '16 at 23:53
  • @jaaq: It.. just does. That's how the language is constructed. Lookup rules have to take into account _all_ facets of the language. Could there be a special case made for `new`? Sure. It would make everything else much more complicated though. And for what? – Lightness Races in Orbit Jun 29 '16 at 23:53
  • My question was why the compiler even tries to pick the enum.. Also searching the web literally helped nothing, this might help someone in the future.. – jaaq Jun 29 '16 at 23:54
  • 2
    with `new 52` at least we would have gotten comic books. – user4581301 Jun 29 '16 at 23:56
  • Because that's the way the language is constructed. I cannot give you a better answer than that, because there isn't one. If you can tell us more about what sort of answer you're looking for, perhaps we'll have better luck together. – Lightness Races in Orbit Jun 29 '16 at 23:57
  • It apears that the answer indeed comes down to a simple "just because". I just thought since the compiler considered to use the enum with new there might be some weird feature with new and enums I somehow never stumbled upon. – jaaq Jun 30 '16 at 00:00