未命名命名空间内部函数和外部函数之间的歧义

19
考虑以下代码片段:
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).
}

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

19
你无法这样做。标准中包含以下部分(§7.3.1.1,C++03):

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

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

在翻译单元中所有出现的 unique 都被替换为相同的标识符,并且此标识符与整个程序中的所有其他标识符不同。

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

但您可以使用类似以下内容的技术代替:

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是全局作用域中的Foo。我根本不需要使用作用域解析运算符。关于这个问题的方面您有什么想法吗? - sharp02
关于你的编辑--那基本上就是我现在正在做的,只不过我使用一个包装函数来获取实际的目标函数。 - sharp02
@sharp:在该作用域中有两个符号 Foo。考虑一个等效的情况:namespace A { int i; } namespace B { int i; } using namespace A; using namespace B; - Georg Fritzsche
好观点,但从语言角度来看,这似乎仍然有些丑陋。 =\ - sharp02
@sharp:丑陋的是有两个同名函数。 :) - GManNickG
@GMan:不,这个太丑了;) - Georg Fritzsche

5

虽然Georg提供了符合标准、正确、合适和值得尊重的答案,但我想提供一个hacky的答案 - 在匿名命名空间内使用另一个命名空间

#include <iostream>

using namespace std;

namespace
{
namespace inner
{
    int cout = 42;
}
}

int main()
{
    cout << inner::cout << endl;
    return 0;
}

2
我能想到的唯一不修改现有命名空间结构的解决方案是将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();
}

0

唯一真正的方法是将您想要访问该命名空间的代码放在命名空间本身内部。否则,无法解析到未命名的命名空间,因为它没有标识符可供您解决模糊的解析问题。

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


0

只需将本地命名空间函数重新命名即可。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接