为啥内联未命名的命名空间?

Posted

技术标签:

【中文标题】为啥内联未命名的命名空间?【英文标题】:Wherefore inline unnamed namespaces?为什么内联未命名的命名空间? 【发布时间】:2013-12-11 02:17:02 【问题描述】:

给专家的快速提示:C++11 允许将未命名的命名空间声明为 inline。这对我来说似乎是多余的;在未命名的命名空间中声明的东西已经被使用,就好像它们是在封闭的命名空间中声明的一样。

所以我的问题是:这是什么意思

inline namespace /*anonymous*/ 
    // stuff

和传统的有什么不同

namespace /*anonymous*/ 
    // stuff

我们从 C++98 开始了解和喜爱?谁能举例说明使用inline 时的不同行为?

编辑: 澄清一下,因为这个问题已被标记为重复:我一般不会询问 named 内联命名空间。我了解那里的用例,我认为它们很棒。我特别想问将 unnamed 命名空间声明为inline 意味着什么。由于未命名的命名空间必须始终是 TU 的本地名称,因此符号版本化理性似乎并不适用,所以我很好奇添加 inline 实际上会做什么


顺便说一句,关于未命名命名空间的标准 [7.3.1.1] 说:

inline 出现当且仅当它出现在 unnamed-namespace-definition

但这在我的非语言律师眼中似乎是同义反复——“它出现在定义中,当且仅当它出现在定义中”!对于加分,谁能解释一下这句标准话到底在说什么?

编辑: Cubbi 在 cmets 中获得了奖励积分:

标准是说 unnamed-namespace-definition 的行为就好像它被 X 替换了,其中inline 出现在 X 中它出现在 unnamed-namespace-definition

【问题讨论】:

What are inline namespaces for? 的可能重复项 @Jefffrey,这是关于 未命名 内联命名空间的。 @chris,我认为你可以混合 unnamedinline 命名空间的定义来得出答案。 @Jefffrey 这个问题一般是关于内联命名空间的,我理解。这个问题是专门询问 unnamed 命名空间为 inline 意味着什么,链接的答案(或我能找到的任何其他 SO 问题)似乎没有涵盖这一点。跨度> 加分点很简单:标准是说 unnamed-namespace-definition 的行为就好像它被替换为 X 其中inline如果它出现在 unnamed-namesace-definition 中,则出现在 X 【参考方案1】:

这是我发现的一种用途:

namespace widgets  inline namespace 

void foo();

  // namespaces

void widgets::foo()


在本例中,foo 具有内部链接,我们可以稍后使用namespace::function 语法定义函数,以确保函数的签名正确。如果您不使用widgets 命名空间,那么void foo() 定义将定义一个完全不同的函数。您也无需重新打开命名空间,从而为您节省一定程度的缩进。

如果在小部件 namespace 中已经有另一个名为 foo 的函数,那么这会给您带来歧义,而不是令人讨厌的 ODR 违规。

【讨论】:

我不确定我是否理解您在这里所做的事情。为什么需要内部inline namespace @templatetypedef 内部的inline namespace 提供foo 内部链接。外部namespace 是为了让您可以使用namespace::function 语法来定义它,确保您获得正确的签名。 啊,有道理。您可能需要更新您的答案以明确指出这一点,因为我第一次没有选择。 酷,我喜欢这个!但 Clang 似乎没有:我得到 “'foo' 的外线定义与命名空间'widgets' 中的任何声明都不匹配”。不过它与 g++ 一起工作得很好,所以也许这只是一个 Clang 错误。 @NirFriedman 没有inline,如果不再次打开未命名的命名空间,您将无法定义foo 函数。【参考方案2】:

我不知道在SO上回答你自己的问题是否已经完成,但是在玩了一些之后我的好奇心得到了满足,所以我不妨分享一下。

内联命名空间的定义不仅包括将名称提升到封闭的命名空间中(无论如何都会发生在未命名的命名空间中),而且还允许在内联命名空间内定义的模板在其外部专门化。事实证明,这也适用于未命名的命名空间:

inline // comment this out to change behaviour
namespace  
    template <typename T> struct A ;


template <> struct A<int> ;

如果没有inline,g++ 会抱怨试图从不同的命名空间特化模板(尽管 Clang 不会)。使用inline,它编译得很好。对于这两种编译器,在专业化中定义的任何内容仍被标记为具有内部链接(根据nm),就好像它在未命名的命名空间中一样,但我想这是可以预料的。我真的想不出这有什么用处,但我们开始了。

一个可以说更有用的效果来自关于内联命名空间的依赖于参数的查找的变化,这也会影响未命名的内联命名空间。考虑以下情况:

namespace NS 
    // Pretend this is defined in some header file
    template <typename T>
    void func(const T&) 

    // Some type definition private to this TU
    inline namespace 
        struct A ;
    

 // end namespace NS

int main()

    NS::A a;
    func(a);

没有inline,ADL 会失败,我们必须显式写入NS::func(a)。当然,如果我们在顶层定义了未命名的命名空间(就像通常那样),那么无论它是否是内联的,我们都不会得到 ADL,但仍然......

【讨论】:

以上是关于为啥内联未命名的命名空间?的主要内容,如果未能解决你的问题,请参考以下文章

为啥要将类型放在未命名的命名空间中?

为啥未命名的命名空间是静态的“优越”替代品? [复制]

命名空间

封闭命名空间内联时的嵌套命名空间定义

JAXB:为啥在生成的 xml 文档中未使用定义的命名空间前缀?

内联命名空间中对命名空间的不明确引用