C++11 内联命名空间与直接在封闭命名空间中嵌入类型

C++11 inline namespace vs embedding the types directly in the enclosing namespace

本文关键字:命名空间 类型 C++11      更新时间:2023-10-16

阅读和研究大量有关新的 C++11 功能 - "内联命名空间"的信息 我不明白这个功能的真正好处是什么。

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

编辑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

最后这样做。内联移动到"下一个"命名空间制作 它是默认值。仍然允许用户访问"当前",但 使用显式 ::当前 - 即这样:顶级::当前::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

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

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),则需要通知他们现在需要更新他们的用法。 因此,这表明,即使使用内联命名空间,仍然需要将思想放入程序员和他的客户之间的契约中。