26

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

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

inline namespace /*anonymous*/ {
    // stuff
}

以及它与传统的有何不同

namespace /*anonymous*/ {
    // stuff
}

我们从 C++98 了解和喜爱的东西?任何人都可以举例说明inline使用时的不同行为吗?

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


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

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

但这在我的非语言律师眼中似乎是同义反复——“如果它出现在定义中,它就出现在定义中”!对于加分,任何人都可以解释这个标准的实际意思吗?

编辑: Cubbi 在评论中声称加分:

标准是说未命名命名空间定义的行为就好像它被替换为出现在X中的X如果它出现在未命名命名空间定义中inline

4

2 回答 2

15

我不知道在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,但仍然......

于 2013-11-26T08:41:48.723 回答
8

这是我发现的一种用途:

namespace widgets { inline namespace {

void foo();

} } // namespaces

void widgets::foo()
{
}

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

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

于 2013-11-26T08:35:40.617 回答