使用内联命名空间进行API版本管理

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

我想在一个库的API中引入一个突破性的变化(海星),而不破坏用户。因此,我想提供一种方法,让客户以自己的速度迁移到新的API。为此,我想使用内联命名空间。基本的想法很简单,你引入了一个叫做 namespace v1 的旧版本和一个 inline namespace v2 为新的(或反过来)。这一点在 https:/foonathan.net201811inline-namespaces。. 当你想引入另一个突破性的变化时,麻烦就开始了。namespace v3. 让我们有一些示例代码作为进一步讨论的基础。

namespace v1 {
    int foo(); // old version of foo
}

inline namespace v2 {
    std::string foo(); // new, incompatible version of foo
    int bar(); // old version of bar
}

namespace v3 {
    std::string bar(); // new, incompatible version of bar
}

现在,如果我想更新默认的API版本到v3,也就是让v3版本的 bar() 默认为可用,我可以让 namespace v3 inline. 我们已经到了我的两难境地:如果我使 只是 v3 inline 我打破我的客户已经迁移到使用最新的。v2foo() (因此在使用它时没有使用命名空间限定符)。如果我把这两个 v2v3 inline,使所有函数的最新版本都能在全局(库)命名空间中被访问,我引入了一个在 v3::bar()v2:bar(). 如果我移动 v2::foo()v3我的客户刚刚开始迁移到 v2::foo() 并以完全限定的名称(::v2::foo()). 另一种选择是在命名空间中重新声明所有最新版本的函数,对应于最新的API版本,并且只做那个 inline. 这是个很大的重复,还有一些额外生成的代码。有没有更优雅的解决方案?

也有人建议我只用 using v2::bar 里边 inline namespace v3 以将所有符号的最新版本导出到最新的内联命名空间。但据我所知,这破坏了ADL。

c++ api-design
1个回答
1
投票

我最终采用了一个解决方案,这个方案并不像我想要的那么好,那么优雅,但它很简单,也很有效。我的解决方案是为每个突破性的变化引入两个新的api版本。就我在问题中的例子而言,我做了以下的工作。

namespace v1 {
    int foo(); // old version of foo
}

inline namespace v2 {
    std::string foo(); // new, incompatible version of foo

namespace v3 {
    int bar(); // old version of bar
}

inline namespace v4 {
    std::string bar(); // new, incompatible version of bar
}

奇数的版本代表被废弃的变化符号的版本,而偶数的版本代表新的版本。这个系统是可扩展的、简单的和强大的,然而它有点不直观,绝对不优雅。我有预处理程序宏,允许客户端选择默认的 "api版本"。例如,如果一个客户端还没有准备好使用最新的API,它可以选择API版本3,之后命名空间v2和v3将被内联。在他们迁移到最新的API之后,他们可以将API版本提升到4,这样就会出现上面看到的状态。

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