【问题标题】:Anonymous Namespace Ambiguity匿名命名空间歧义
【发布时间】:2025-12-03 20:45:01
【问题描述】:

考虑以下 sn-p:

void Foo() // 1
{
}

namespace
{
  void Foo() // 2
  {
  }
}

int main()
{
  Foo(); // Ambiguous.
  ::Foo(); // Calls the Foo in the global namespace (Foo #1).

  // I'm trying to call the `Foo` that's defined in the anonymous namespace (Foo #2).
}

在这种情况下,我如何引用匿名命名空间中的内容?

【问题讨论】:

    标签: c++ namespaces anonymous ambiguity


    【解决方案1】:

    你不能。该标准包含以下部分(§7.3.1.1,C++03):

    一个未命名的命名空间定义的行为就像它被替换了一样

      namespace unique { /* empty body */ }
      using namespace unique;
      namespace unique { namespace-body }
    

    其中所有出现的唯一性都在 翻译单元被替换为 相同的标识符和这个标识符 不同于整个程序中的所有其他标识符。

    因此您无法引用该唯一名称。

    但是,从技术上讲,您可以改用以下内容:

    int i;
    
    namespace helper {
        namespace {
            int i;
            int j;
        }
    }
    
    using namespace helper;
    
    void f() { 
        j++; // works
        i++; // still ambigous
        ::i++; // access to global namespace
        helper::i++; // access to unnamed namespace        
    }
    

    【讨论】:

    • 好的,标准所说的有道理。但是,为什么会有歧义呢?如果我无法访问匿名命名空间中的 Foo,编译器应该能够推断出唯一的另一个 Foo 是全局范围内的。我根本不必使用范围解析运算符。对问题的这方面有什么想法吗?
    • 回复:您的编辑——这几乎就是我现在正在做的事情,除了我使用包装函数来获取实际的目标函数。
    • @sharp:该范围内有两个符号Foo。考虑一个等效的情况:namespace A { int i; } namespace B { int i; } using namespace A; using namespace B;
    • 好点,但从语言的角度来看,这仍然有点难看。 =\
    • @sharp: Ugly 有两个同名的函数。 :)
    【解决方案2】:

    虽然 Georg 给出了符合标准、正确、正确和可敬的答案,但我想提供一个我的老生常谈 - 在匿名命名空间中使用另一个命名空间

    #include <iostream>
    
    using namespace std;
    
    namespace
    {
    namespace inner
    {
        int cout = 42;
    }
    }
    
    int main()
    {
        cout << inner::cout << endl;
        return 0;
    }
    

    【讨论】:

      【解决方案3】:

      我能想到的唯一不修改现有命名空间安排的解决方案是将main 委托给匿名命名空间中的函数。 (main 本身必须是全局函数(第 3.6.1/1 节),因此不能在匿名命名空间中。)

      void Foo() // 1
      {
      }
      
      namespace
      {
        void Foo() // 2
        {
        }
      }
      
      namespace { // re-open same anonymous namespace
      
          int do_main()
          {
            Foo(); // Calls local, anonymous namespace (Foo #2).
            ::Foo(); // Calls the Foo in the global namespace (Foo #1).
      
            return 0; // return not optional
          }
      
      }
      
      int main() {
          return do_main();
      }
      

      【讨论】:

        【解决方案4】:

        唯一真正的方法是将要访问该命名空间的代码放在命名空间本身中。否则没有办法解析到未命名的命名空间,因为它没有标识符,你可以给它来解决不明确的解析问题。

        如果您的代码在 namespace{} 块本身内,则本地名称优先于全局名称,因此 Foo() 将调用命名空间内的 Foo(),而 ::Foo() 将调用全局范围内的命名空间。

        【讨论】:

          【解决方案5】:

          只需重命名本地命名空间函数。

          【讨论】: