名前空間 A と名前空間 B::A は共存できるか?

ちょっとした実験.

  namespace A {...}
  namespace B { namespace A {...} ... }

のように,既に存在している名前空間 A と同じ識別子の名前空間を,別の名前空間 B の中に作ることはできるか? また,作られた場合どうやってアクセスするのか? を調べる.
最初の例:

#include <iostream>
namespace base
{
  namespace A  // base::A
  {
    int hoge (10);
  }
  namespace B
  {
    namespace A  // base::B::A
    {
      void print(void)
      {
        using namespace std;
        cout<< "hoge= "<< base::A::hoge <<endl;
      }
    }
  }
}

このコードは問題なくコンパイルでき*1

  base::B::A::print();

とすれば print() 関数を呼び出せる.上のコードでは base::A::hoge のように hoge にアクセスしているが,以下のようなコードはエラーとなる:

cout<< "hoge= "<< hoge <<endl;
  // error: 'hoge' was not declared in this scope
cout<< "hoge= "<< A::hoge <<endl;
  // error: 'hoge' is not a member of 'base::B::A'

上のコードの,最初の A は base::A として,次の A は base::B::A としてコンパイラに認識されている. base::B::A::print において, hoge とした場合にも A::hoge とした場合にも base::B::A::hoge を意味することになるから,これらのようなエラーが発生するのだ. base::A::hoge のように正確に指定することで,最初の A の中の hoge にアクセスできる.

では,名前空間 base がなかったらどなるのか? 結論は ::A::hoge のようにアクセスすればいい.

#include <iostream>
namespace A
{
  int hoge (20);
}
namespace B
{
  namespace A
  {
    void print(void)
    {
      using namespace std;
      cout<< "hoge= "<< ::A::hoge <<endl;
    }
  }
}

以下のような指定だとエラーとなる:

cout<< "hoge= "<< hoge <<endl;
  // error: 'hoge' was not declared in this scope
cout<< "hoge= "<< A::hoge <<endl;
  // error: 'hoge' is not a member of 'B::A'

base がない場合は,最初の A は無名名前空間の中に作られるので ::A としてコンパイラに認識され, B の中の A は ::B::A としてコンパイラに認識されるのである.

一番最初の例では,実は ::base::A::hoge という指定がもっとも正確だ.しかし共通の名前空間 base があるから先頭の :: を省略できたのだ.

*1:g++ に -ansi -pedantic オプションをつけて,ANSI準拠モードでコンパイルした.