如果在另一个命名空间中声明了类模板,为什么我不能在未命名的命名空间中显式实例化该类模板?

问题描述 投票:0回答:4

在 C++ 中,您可以通过将类和函数定义包装在未命名的命名空间内来指定内部链接。您还可以显式实例化模板,但为了符合标准,模板的任何显式实例化必须发生在同一命名空间中。 AFAICT 这应该可以编译,但是 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 '::')

:/

c++ namespaces global linkage unnamed-namespace
4个回答
10
投票

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

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

命名空间,无论是匿名的还是其他的,对其成员的链接没有影响。特别是匿名命名空间的成员不会神奇地获得内部链接。


7
投票

首先:您正在显式实例化类模板,而不是定义新的类模板。什么

template class bar<int>;

说的是“请在此处实例化 int 类型的类模板栏”。您无法在另一个名称空间中执行此操作,就像您无法在另一个名称空间中部分特化类模板一样。特别是,必须已定义要显式实例化的模板,并且在您的示例中,没有 (匿名命名空间)::bar<>,只有 foo::bar<>。

第二:匿名命名空间是一个真正的命名空间(尽管它在每个翻译单元中都是不同的)。它也不会神奇地改变链接。命名空间 {} 内声明的所有内容仍具有默认链接,就像在任何其他命名空间范围内一样。 IIRC,甚至添加了它以允许翻译单元私有但外部链接的对象。


6
投票

我想你已经有了答案——匿名命名空间是独特的、唯一的命名空间。顺便说一句,编译器会生成一些随机大整数来在内部表示该名称空间。


0
投票

根据 Stroustrup(第 8.2.5.1 节),全局名称空间可以访问匿名(未命名)名称空间,但没有明确说明相反的情况。

我希望您必须使用 using 语句指定名称空间,或者完全限定对未命名名称空间内其他名称空间的引用...

© www.soinside.com 2019 - 2024. All rights reserved.