匿名命名空间是否包含所有命名空间?

7

在C++中,您可以通过将类和函数定义包装在匿名命名空间中来指定内部链接。您还可以显式实例化模板,但为了符合标准,模板的任何显式实例化都必须发生在相同的命名空间中。据我所知,这应该编译,但GCC无法执行:

namespace foo {

template<class T>
class bar {};

}

using namespace foo;

namespace {
template class bar<int>;
}

int main()
{
    return 0;
}

出现以下错误:

namespace_test.cpp:11: error: explicit instantiation of 'class bar<int>' in namespace '<unnamed>' (which does not enclose namespace 'foo')

这很有趣,因为匿名命名空间应该只是指定链接,而不是真正作为命名空间,全局命名空间肯定包含foo,因为它包含每个命名空间。但即使这样也不行!

template<class T>
class bar {};

using namespace foo;

namespace {
template class bar<int>;
}

int main()
{
    return 0;
}

同样出现错误,只是列出了全局命名空间:

namespace_test.cpp:11: error: explicit instantiation of 'class bar<int>' in namespace '<unnamed>' (which does not enclose namespace '::')

:/


哪个版本的GCC - 或者哪些编译器选项 - 或者哪个平台?我在MacOS X上尝试了第一个示例,使用G++ 4.0.1,带或不带-Wall都可以编译而没有任何警告。 - Jonathan Leffler
4个回答

10

匿名命名空间在逻辑上等同于

namespace _TU_specific_unique_generated_name
{
    // ...
}
using namespace _TU_specific_unique_generated_name;

命名空间,无论是匿名的还是非匿名的,对其成员的链接没有影响。特别是匿名命名空间的成员并不会自动获得内部链接。


1
我会补充明显的一点,即 _TU_specific_unique_generated_name 中的内容无法在文件外部使用。 - Valentein
这确实是标准中描述的方式,被广泛接受。 - Joseph Garvin

7

首先:您正在显式实例化一个类模板,而不是定义一个新的类模板。这意味着您正在根据现有的模板创建一个具体的类。

template class bar<int>;

说的是“请在此处实例化类型为int的类模板bar”。您不能在另一个命名空间中执行此操作,就像您不能在另一个命名空间中部分特化类模板一样。特别地,要明确实例化的模板必须已定义,在您的示例中,没有(匿名名称空间)::bar<>,只有foo::bar<>。
其次,匿名名称空间是一个真正的名称空间(尽管在每个翻译单元中都是不同的)。它也不会神奇地改变链接。在namespace {}内声明的所有内容仍具有默认链接,就像在任何其他名称空间作用域中一样。如果我没记错,它甚至被添加以允许翻译单位专用的、具有外部链接的对象。

6
我认为你已经得到了答案 - 匿名命名空间是独特的、唯一的命名空间。顺便说一下,编译器会生成一些随机的大整数来表示该命名空间的内部值。

0

根据Stroustrup(8.2.5.1节),全局命名空间可以访问匿名(未命名)命名空间,但它并没有明确说明反之亦然。

我预计你需要使用using语句指定命名空间,或者在未命名的命名空间内完全限定其他命名空间的引用...


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