在.cc文件中,提倡使用不具名命名空间。如果使用具名命名空间,基于项目或路径名称而不是using指示符 (例如 using namespace foo
) 禁止使用内联 (inline) 命名空间 。命名空间内不用缩进。
定义:命名空间可以将全局作用域 (global scope) 划分为独立的、有名字的作用域, 因此可以有效防止全局作用域中的命名冲突 (name collision).
优点:命名空间可以避免大型程序中的命名冲突, 同时代码可以继续使用简短的名称.
举例来说, 若两个项目的全局作用域中都有一个叫 Foo
的类 (class), 这两个符号 (symbol) 会在编译或运行时发生冲突. 如果每个项目在不同的命名空间中放置代码, project1::Foo
和 project2::Foo
就是截然不同的符号, 不会冲突.
内联命名空间会自动把其中的标识符置入外层作用域, 比如:
namespace outer {
inline namespace inner {
void foo();
} // namespace inner
} // namespace outer
此时表达式 outer::inner::foo()
与 outer::foo()
等效. 内联命名空间的主要用途是保持不同 ABI 版本之间的兼容性。
缺点:不具名命名空间容易违背C++中唯一定义的原则.部分情景下, 我们必须多次使用完全限定名称 (fully-qualified name) 来引用符号. 此时多层嵌套的命名空间会让代码冗长. 。
结论:建议按如下方法使用命名空间:
遵守 命名空间命名 规则.
像前面的例子一样, 用注释给命名空间收尾. (译者注: 注明命名空间的名字.)
在导入语句、 gflags 声明/定义以及其他命名空间的类的前向声明 (forward declaration) 之后, 用命名空间包裹整个源代码文件:
// .h 文件 namespace mynamespace { // 所有声明都位于命名空间中. // 注意没有缩进. class MyClass { public: ... void Foo(); }; } // namespace mynamespace
// .cc 文件 namespace mynamespace { // 函数定义位于命名空间中. void MyClass::Foo() { ... } } // namespace mynamespace
更复杂的
.cc
文件有更多细节, 比如旗标 (flag) 或 using 声明.#include "a.h" DEFINE_FLAG(bool, someflag, false, "某个旗标"); namespace mynamespace { using ::foo::Bar; ...命名空间内的代码... // 代码紧贴左边框. } // namespace mynamespace
若要将自动生成的 proto 消息代码放入命名空间, 可以在 .proto
文件中使用 package
修饰符 (specifier). 参见 Protocol Buffer 的包.
不要在 std
命名空间内声明任何东西. 不要前向声明 (forward declare) 标准库的类. 在 std
命名空间内声明实体是未定义行为 (undefined behavior), 也就是会损害可移植性. 若要声明标准库的实体, 应该导入对应的头文件.
禁止使用 using 指令 引入命名空间的所有符号。
// 禁止: 这会污染命名空间. using namespace foo;
除了在明显标注为内部使用的命名空间内, 不要让头文件引入命名空间别名 (namespace alias). 这是因为头文件的命名空间中引入的任何东西都是该文件的公开 API. 正确示例:
// 在 .cc 中, 用别名缩略常用的名称. namespace baz = ::foo::bar::baz;
// 在 .h 中, 用别名缩略常用的命名空间. namespace librarian { namespace impl { // 仅限内部使用, 不是 API. namespace sidetable = ::pipeline_diagnostics::sidetable; } // namespace impl inline void my_inline_function() { // 一个函数 (f或方法) 中的局部别名. namespace baz = ::foo::bar::baz; ... } } // namespace librarian
禁止内联命名空间.
如果命名空间的名称包含 “internal”, 代表用户不应该使用这些 API.
// Absl 以外的代码不应该使用这一内部符号. using ::absl::container_internal::ImplementationDetail;
我们鼓励新的代码使用单行的嵌套命名空间声明, 但不强制要求.
译者注: 例如
namespace foo::bar { ... } // namespace foo::bar