使用内联命名空间的 API 版本控制
Posted
技术标签:
【中文标题】使用内联命名空间的 API 版本控制【英文标题】:API versioning with inline namespaces 【发布时间】:2020-08-03 23:36:36 【问题描述】:我想对库 (seastar) 的 API 进行重大更改,但不会影响用户。所以我想为客户提供一种按照自己的节奏迁移到新 API 的方法。为此,我想使用内联命名空间。基本思想很简单,您为旧版本引入namespace v1
,为新版本引入inline namespace v2
(或相反)。这在https://foonathan.net/2018/11/inline-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
我会破坏我的客户,他们已经迁移到使用最新的v2
版本的foo()
(因此正在使用它)没有命名空间限定符)。如果我同时创建v2
和v3
inline
,以便可以在全局(库)命名空间中访问所有函数的最新版本,我会在v3::bar()
和v2:bar()
之间引入歧义。如果我将 v2::foo()
移动到 v3
,我会破坏刚开始迁移到 v2::foo()
并使用完全限定名称 (::v2::foo()
) 的客户。另一种选择是在与最新 API 版本相对应的命名空间中重新声明所有最新版本的函数,并仅生成 inline
。这是很多重复和一些额外生成的代码。有没有更优雅的解决方案?
我还被建议只在inline namespace v3
中使用using v2::bar
(等等)将所有符号的最新版本导出到最新的内联命名空间中。然而,据我所知,这会破坏 ADL。
【问题讨论】:
【参考方案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,这将导致上述状态。
【讨论】:
以上是关于使用内联命名空间的 API 版本控制的主要内容,如果未能解决你的问题,请参考以下文章