匿名命名空间

在 C/C++ 的源文件中,为了对外隔离符号,即外界无法通过 extern 声明捕获到这个符号,我们一般会采用 static 声明的方式来处理这个符号。比如

// 采用static声明对外隐藏符号
static void internal_func();

static float internal_value;

这样, internal_funcinternal_value 这两个符号对外就是不可见的了。一般情况下,隐藏符号只通过 static 声明就可以了,但 static 声明也有如下缺点:

1、static 无法修饰类型,比如这样的类型声明就是错误的。

// 注意:这段代码是非法的
static class Widget {
public:
    ...
};

因此,如果想要隐藏 Widget 这个类,就不能用 static 声明的方式。

2、static 这个关键词用处过多,在不同的地方修饰的变量,其含义完全不同,容易造成混淆。比如下面定义的三个 static 变量,其含义就完全不同

class Widget
{
private:
    static float count;
};

static const float PI = 3.141592654;

void test()
{
    static int i = 0;
    ...
}

3、由于 static 声明会使得符号没有外部链接属性,因此某些模板参数将不能使用这个符号,比如

template<typename T, const int& N>
class Widget
{
public:
    ...
private:
    T data[N];
    ...
};

static const int kMaxSize = 30;

Widget<int, kMaxSize> w;   // 报错,因为kMaxSize并不具备外部链接属性

为了克服上述三个缺点,就需要引入另一种隐藏符号的方式——匿名命名空间。我们先来看这样一段声明

// 采用匿名命名空间对外隐藏符号
namespace {

void internal_func();

float internal_value;

}

在这段声明中,注意我们并没有指定 namespace 是什么。这种没有为 namespace 指定名字的命名空间就是所谓的“匿名命名空间”。

阅读余文匿名命名空间