Discussion:
Namespace vs. class ambiguity: three compilers - three different outcomes
(too old to reply)
Andrey Tarasevich
2024-09-07 18:24:31 UTC
Permalink
Hello

It is illegal to just flat-out declare a class and a namespace with
identical names in the same scope

namespace N {}
class N {}; // <- Not allowed

However, one can try to circumvent the direct restriction by means of
using-directive or using-declaration

#include <iostream>

namespace N
{
void foo() { std::cout << "namespace" << std::endl; }
}

namespace X
{
struct N
{
static void foo() { std::cout << "class" << std::endl; }
};
}

using X::N;
// or
// using namespace X;

int main()
{
N::foo();
}

GCC is perfectly happy with either version of this code (both
using-declaration and using-directive versions are OK). It simply
resolves the call to the "namespace" version of `foo()`.

Clang issues an error: it complains about the call being ambiguous. I.e.
the error is issued at the point of the call.

MSVC++ issues an error for `using X::N;` at the point of
using-declaration: it basically says that `N` already exists in this
scope. But if we switch to `using namespace X;` version, MSVC++ will
exhibit Clang-like behavior: complain about ambiguity at the point of
the call.

So, who is right here?
--
Best regards,
Andrey

P.S. We can rewrite `main` as

int main()
{
using T = struct N;
T::foo();
}

This will keep both GCC and Clang happy and direct the call to the
"class" version of `foo()`. It will work in both using-declaration and
using-directive versions of the code

This will work in MSVC++ as well, but obviously only with
using-directive version (since using-declaration triggers an error earlier).

Again, who is right here?
Bonita Montero
2024-09-07 18:42:26 UTC
Permalink
Post by Andrey Tarasevich
Hello
It is illegal to just flat-out declare a class and a namespace with
identical names in the same scope
  namespace N {}
  class N {}; // <- Not allowed
However, one can try to circumvent the direct restriction by means of
using-directive or using-declaration
  #include <iostream>
  namespace N
  {
    void foo() { std::cout << "namespace" << std::endl; }
  }
  namespace X
  {
    struct N
    {
      static void foo() { std::cout << "class" << std::endl; }
    };
  }
  using X::N;
  // or
  // using namespace X;
  int main()
  {
    N::foo();
  }
GCC is perfectly happy with either version of this code (both using-
declaration and using-directive versions are OK). It simply resolves the
call to the "namespace" version of `foo()`.
Clang issues an error: it complains about the call being ambiguous. I.e.
the error is issued at the point of the call.
MSVC++ issues an error for `using X::N;` at the point of using-
declaration: it basically says that `N` already exists in this scope.
But if we switch to `using namespace X;` version, MSVC++ will exhibit
Clang-like behavior: complain about ambiguity at the point of the call.
So, who is right here?
Does it really matter or is it just sufficient to prevent such code ?
Andrey Tarasevich
2024-09-10 04:31:11 UTC
Permalink
Post by Bonita Montero
Does it really matter or is it just sufficient to prevent such code ?
Dark corners like that belong to the same ballpark as, say, that popular
"niebloid" trickery everyone appears to be so exited about. When the
need for such tricks arises, yeah, it might matter.
--
Best regards,
Andrey
Andrey Tarasevich
2024-09-10 04:27:41 UTC
Permalink
Post by Andrey Tarasevich
Clang issues an error: it complains about the call being ambiguous. I.e.
the error is issued at the point of the call.
MSVC++ issues an error for `using X::N;` at the point of
using-declaration: it basically says that `N` already exists in this
scope. But if we switch to `using namespace X;` version, MSVC++ will
exhibit Clang-like behavior: complain about ambiguity at the point of
the call.
More precisely, it is not the call that's ambiguous. These compilers do
not even get to the call itself. They complain about the ambiguity of
`N` and just stop there. Which means that trying to "resolve" this
ambiguity by renaming one of the functions is not going to make any
difference.

GCC also "resolves" at the `N` stage. It just ignores the class entirely.
--
Best regards,
Andrey
Loading...