Skip to the content.

C++ namespace

文件 重点
basic.cpp 同名函数、全局限定、嵌套、别名、using、inline namespace
adl.cpp 根据实参类型查找函数、hidden friend、通用 swap
counter.hpp、counter.cpp、counter-main.cpp 跨文件声明与定义、匿名命名空间、链接

3. 几种容易混淆的 using

写法 含义
using std::cout; using-declaration,将指定名字引入当前作用域
using namespace std; using-directive,使该命名空间的名字参与查找
using Count = int; 类型别名,Count 是 int 的另一种名字
namespace fs = app::filesystem; 命名空间别名,使用 namespace 关键字
void print() {
    using std::cout;
    cout << "hello\n";
}

using std::cout 的影响限制在这里的函数块内。它不会复制一个 cout 对象。 如果引入的是函数名,会引入声明处可见的同名重载,而不是只选一个函数。 类型别名的更多用法见 template/alias.md。

4. namespace 和头文件、链接的关系

counter.hpp 在 namespace tutorial 中声明 next(); counter.cpp 再打开它并提供定义; counter-main.cpp 包含头文件并调用 tutorial::next()。 编译器分别处理两个 .cpp,链接器再把函数调用与定义连接起来。

namespace 不会改变“非 inline 普通函数通常只能定义一次”的规则。 下面的头文件如果被多个 .cpp 包含,通常会在链接时报重复定义:

// bad.hpp
namespace tutorial {
    int answer() { return 42; } // namespace 并不能消除重复定义
}

可以在头文件只写声明,把定义放到一个 .cpp;也可以在确实需要头文件定义时 写 inline int answer() { return 42; },并满足 ODR 对多份定义的要求。 #pragma once 或 include guard 只避免同一个翻译单元内重复包含,不能解决跨 翻译单元的重复定义。翻译单元可以先理解为一个 .cpp 加上它包含的头文件。

命名空间作用域变量也要注意:普通可变变量可用头文件 extern 声明加单个 .cpp 定义;C++17 起,也可以用 inline 变量在头文件定义共享实体。

5. 匿名命名空间:只属于这个翻译单元

namespace {
    int count = 0;
    int increment() { return ++count; }
}

这里的变量和函数具有内部链接。另一个 .cpp 写相同代码,得到的是自己那份 count 和 increment,不会与这里的实体合并。 同一个作用域内的匿名命名空间在同一翻译单元中重新打开,仍然是同一个。 规则见 Unnamed namespaces。

通常把 .cpp 内部的辅助函数、变量、类型放进去。它也适用于类型,而命名空间 作用域的 static 常用于让函数或变量具有内部链接。 匿名命名空间不是权限隔离:本翻译单元中后续代码仍然可以通过名字查找使用它。

不要把需要跨文件共享的状态或类型放进头文件的匿名命名空间:每个包含它的 翻译单元都会得到独立实体。counter.cpp 中的 count 和 counter-main.cpp 中的 count 就是独立变量;运行时前者递增, 后者始终为 100。

6. inline namespace:默认版本的名字可以省一层

namespace library {
    namespace v1 {
        int version() { return 1; }
    }
    inline namespace v2 {       // C++11 起
        int version() { return 2; }
    }
}
// library::version()     -> 2
// library::v2::version() -> 2
// library::v1::version() -> 1

它常用于库接口版本组织:默认暴露 v2,保留显式访问 v1 的路径。 这里的 inline 不要求函数调用被展开;实体仍属于 v2。 它还对 ADL 和模板特化有专门规则,并不完全等同于手写 using namespace v2。 详见标准草案 Namespace definition。 选择一个默认版本本身不能保证任意两个库版本的 ABI 兼容。

8. 实际组织代码时怎么选

本站所有文章转发 CSDN 将按侵权追究法律责任,其它情况随意。