4

consider the following code:

struct foo {
    typedef int bar;
};

namespace foo {
    class baz {
        /* code */
    };
}

This is spread over a codebase that I have to work on, and it kind of works sometimes and I don't understand how.

As long as the namespace and the class don't occur in the same source (after preprocessing) it will work (I understand that part). However if suddenly both the namespace and the class are dragged into the same compilation unit by the preprocessor it (might) clash (I don't know if this ever occurs in the source).

Is there a convention that allows the compiler to always resolve code structures as those correctly? The most logical would be the forbid by namespaces and classes to have same symbols. The applied coding style allows clashing namespaces with classes albeit the ambiguity thus I would prefer a way to tell the compiler on usage instead of changing the coding convention.

something like:

use_namespace(foo)::baz b; 
use_class(foo) b;
Alexander Oh
  • 24,223
  • 14
  • 73
  • 76
  • 2
    You can not have foo being a class/struct and namespace at the same time, so there is no question how to disambiguate it. – PlasmaHH May 27 '13 at 12:02
  • I've come across this before but am not too sure of the explanation. From what I remember, think they have different names assigned to them by the compiler (mangled names) https://en.wikipedia.org/wiki/Name_mangling. Talking totally with respect to C++. – Nanda May 27 '13 at 12:05
  • 2
    @Nanda: They *might* have different mangled names, but there's no guarantee. It's an error to give a class and a namespace the same name. – Mike Seymour May 27 '13 at 12:22

2 Answers2

11

Paragraph 7.3.1/2 of the C++11 Standard simply forbids that:

The identifier in an original-namespace-definition shall not have been previously defined in the declarative region in which the original-namespace-definition appears. The identifier in an original-namespace-definition is the name of the namespace. Subsequently in that declarative region, it is treated as an original-namespacename.

Concerning this statement of yours:

As long as the namespace and the class don't occur in the same source (after preprocessing) it will work

That's incorrect. Paragraph 7.3.2/4 (and the last sentence in particular) tells you why it seems to be "working", although your program is ill-formed:

A namespace-name or namespace-alias shall not be declared as the name of any other entity in the same declarative region. A namespace-name defined at global scope shall not be declared as the name of any other entity in any global scope of the program. No diagnostic is required for a violation of this rule by declarations in different translation units.

This means the codebase you are working with has undefined behavior, and this is potentially a time bomb that may explode in incomprehensible ways.

Andy Prowl
  • 124,023
  • 23
  • 387
  • 451
  • actually I was afraid of some kind of answer. Although undefined behavior is often behaving deterministic on a single compiler. – Alexander Oh May 27 '13 at 13:15
  • @Alex: But may change behavior in release builds, or when you use a particular compiler setting, or when the next version of the compiler is shipped, or... (and so on and so on). I'd really suggest a re-design – Andy Prowl May 27 '13 at 13:16
  • I agree, but just to point out: Compiler engineers are humans and they know that programmers are human too! So while this is undefined behavior usually compiler writers are trying to help the programmer at fault by either: deliberately crashing the code at the point of failure, trying to to crash the compilation or, if possible at least construct consistent results that undefined behavior will not bite you during your afternoon nap. (i.e.: I haven't seen code that was tested on only one compiler/arch that is still standard compliant.) – Alexander Oh May 27 '13 at 20:33
  • In regards to "after preprocessing" in the quote, does that mean it wouldn't work if the struct and original namespace were declared in different .h files if one file included the other? – Anthony Jul 31 '18 at 16:39
2

As long as the namespace and the class don't occur in the same source (after preprocessing) it will work (I understand that part).

No it doesn't. Declaring the same name for two different entities gives undefined behaviour according to C++11 3.3.1/4:

Given a set of declarations in a single declarative region, each of which specifies the same unqualified name, they shall all refer to the same entity

(with some exceptions which do not include giving a class and a namespace the same name).

Since the declarations are in separate translation units, many compilers can't diagnose the error, so it might appear to work.

However if suddenly both the namespace and the class are dragged into the same compilation unit by the preprocessor it (might) clash (I don't know if this ever occurs in the source).

Now that they are in the same translation unit, the error can be diagnosed.

Mike Seymour
  • 249,747
  • 28
  • 448
  • 644