【问题标题】:C++11 inline namespace vs embedding the types directly in the enclosing namespaceC++11 内联命名空间与将类型直接嵌入封闭命名空间
【发布时间】:2017-04-14 23:57:23
【问题描述】:

阅读和研究了很多关于 C++11 新特性——“内联命名空间”的内容。我不明白这个特性的真正好处是什么。

我可以轻松地将“内联命名空间”中定义的所有函数/类型直接放置在封闭的命名空间中,并获得相同的结果。 那么将函数/类型放入内联命名空间的真正动机是什么? 对功能/类型进行分组? 使用“内联命名空间”是否有任何与 ADL 相关的好处? 我认为 ADL 的行为与此“内联命名空间”的隐式“使用”指令相同。

编辑1:

所以我认为以下是关键优势。 假设最初我们有这个:

namespace toplevel {
     // Users can use toplevel::MyType
     inline namespace current {
           class MyType {};
     } // inline namespace current
} // ns toplevel

现在,有一些新要求,我们需要一个新版本 可用,但保持旧的完整:

namespace toplevel {
     // Users can use toplevel::MyType
     // we can let the users know that we are going to deprecate it
     // in favor of toplvel::next::MyType
     inline namespace current {
           class MyType {};
     } // inline namespace current

     // Users can use toplevel::next::MyType
     namespace next {
           class MyType {};
     } // namespace next

} // ns toplevel

最后做到这一点。内联移动到“下一个”命名空间 它是默认值。仍然让用户访问“当前”但是 显式 ::current - 即这样:toplevel::current::MyType 顺便说一句 - 我的偏好甚至会将“当前”重命名为“已弃用”。

namespace toplevel {
     // Users can still use it by referring
     // to toplevel::current::MyType
     namespace current {
           class MyType {};
     } // inline namespace current

     // Have this one the default one 
     // under toplevel
     // Users can use the new one this way: toplevel::MyType
     inline namespace next {
           class MyType {};
     } // namespace next

} // ns toplevel

这听起来像是一个正确的场景吗?

【问题讨论】:

  • 名称修改和版本链接是一些主要动机。
  • 好的。所以版本控制确实是主要动机之一。再次阅读what-are-inline-namespaces-for,我认为这个想法是能够提供像 std::vector 这样的默认值,但如果新编译器的 std libc++ 的向量不是,则允许用户能够回退到 std::pre_cxx_1997::vector运作良好。所以我想这个不错的功能是使用 lnline 的关键优势。我将编辑我的问题。

标签: c++ c++11 namespaces


【解决方案1】:

C++ 内联命名空间的主要动机确实涉及版本控制。你的理解是正确的,除了你问题中的最后一句话:

我的偏好甚至会将“当前”重命名为“已弃用”

使用内联命名空间的整个想法是命名空间名称不会改变——相反,这个特性允许命名空间名称​​不需要改变;现有名称可以永远存在,而无需对代码进行太多更改。

相反,在发布版本时(当我们过去认为的“当前功能”现在变成“不推荐使用的功能”时),命名空间名称可以保持不变,但它们的默认状态会更新。

让我们在代码中看看:

namespace MyProject {
    namespace Version1 {
        void BoringStableFunction() {...}
    }
    inline namespace Version2 {
        void BoringStableFunction() {...}
        void LatestAndGreatest(int x) {...}
    }
}

该软件的客户可能最常通过简单地调用MyProject::BoringStableFunction() 和MyProject::LatestAndGreatest(11) 来使用它,甚至可能不知道MyProject 存在两个不同的版本。这种便利可能是一件好事。如果客户确实知道有两个不同的版本,并且有意使用旧版本(在LatestAndGreatest() 被发明之前),他仍然可以通过调用MyProject::Version1::BoringStableFunction() 来实现。

请注意,允许客户将其代码编写为MyProject::Version2::BoringStableFunction()。这样做实际上是客户说“我想调用当前的 #2 版本,并且我希望我使用的那个实现保持不变——即使那个 MyProject 项目稍后会更新”

注意我如何在不影响任何现有客户的情况下执行额外的开发:

namespace MyProject {
    namespace Version1 {
        void BoringStableFunction() {...}
    }
    inline namespace Version2 {
        void BoringStableFunction() {...}
        void LatestAndGreatest(int x) {...}
    }
    namespace Version3 {
        void BoringStableFunction() {...}
        void LatestAndGreatest(std::string x) {...}
    }   
}

当我准备好向公众发布我的更改时,只需要进行这个微小的修改:

namespace MyProject {
    namespace Version1 {
        void BoringStableFunction() {...}
    }
    namespace Version2 {
        void BoringStableFunction() {...}
        void LatestAndGreatest(int x) {...}
    }
    inline namespace Version3 {
        void BoringStableFunction() {...}
        void LatestAndGreatest(std::string x) {...}
    }   
}

大多数客户一直在致电MyProject::BoringStableFunction()。他们的代码不需要编辑;它在语法上仍然有效。但他们现在会突然利用我可能在BoringStableFunction() 中更改的任何新实现。

如果他们如此大胆地使用我的MyProject::LatestAndGreatest(11),他们将需要被告知他们现在需要更新他们的使用情况。所以这表明,即使使用内联命名空间,仍然需要将思想纳入程序员与其客户之间的合同中。

【讨论】:

    猜你喜欢
    • 2020-08-07
    • 2020-02-19
    • 1970-01-01
    • 2012-07-23
    • 2015-11-18
    • 1970-01-01
    • 1970-01-01
    • 2017-08-09
    • 2013-03-25
    相关资源
    最近更新 更多