c++的一个特性是能够创建未命名(匿名)的名称空间,如下所示:

namespace {
    int cannotAccessOutsideThisFile() { ... }
} // namespace

您可能会认为这样的特性毫无用处——因为不能指定名称空间的名称,因此不可能从外部访问其中的任何内容。但是,这些未命名的名称空间可以在创建它们的文件中访问,就像对它们有一个隐式的using子句一样。

我的问题是,为什么或者什么时候这比使用静态函数更可取?或者它们本质上是做同一件事的两种方式?


当前回答

根据我的经验,我只想指出,虽然这是c++将以前的静态函数放入匿名名称空间的方式,但旧的编译器有时会在这方面遇到问题。我目前正在使用一些用于目标平台的编译器,更现代的Linux编译器可以很好地将函数放置到匿名名称空间中。

但是在Solaris上运行的旧编译器有时会接受它,有时会将其标记为错误,直到未来未指定的版本发布。我担心的不是这个错误,而是它在接受错误时可能会做什么。因此,在全面现代化之前,我们仍然使用静态(通常是类作用域)函数,我们更喜欢匿名名称空间。

其他回答

此外,如果在变量上使用static关键字,例如:

namespace {
   static int flag;
}

在映射文件中不会看到它

在一种边缘情况下,静电会产生令人惊讶的效果(至少对我来说是这样)。c++ 03标准在14.6.4.2/1中声明:

For a function call that depends on a template parameter, if the function name is an unqualified-id but not a template-id, the candidate functions are found using the usual lookup rules (3.4.1, 3.4.2) except that: For the part of the lookup using unqualified name lookup (3.4.1), only function declarations with external linkage from the template definition context are found. For the part of the lookup using associated namespaces (3.4.2), only function declarations with external linkage found in either the template definition context or the template instantiation context are found. ...

下面的代码将调用foo(void*),而不是你可能期望的foo(S const &)。

template <typename T>
int b1 (T const & t)
{
  foo(t);
}

namespace NS
{
  namespace
  {
    struct S
    {
    public:
      operator void * () const;
    };

    void foo (void*);
    static void foo (S const &);   // Not considered 14.6.4.2(b1)
  }

}

void b2()
{
  NS::S s;
  b1 (s);
}

就其本身而言,这可能不是什么大问题,但它确实强调了对于完全兼容的c++编译器(即支持导出的编译器),static关键字仍然具有其他任何方式都无法提供的功能。

// bar.h
export template <typename T>
int b1 (T const & t);

// bar.cc
#include "bar.h"
template <typename T>
int b1 (T const & t)
{
  foo(t);
}

// foo.cc
#include "bar.h"
namespace NS
{
  namespace
  {
    struct S
    {
    };

    void foo (S const & s);  // Will be found by different TU 'bar.cc'
  }
}

void b2()
{
  NS::S s;
  b1 (s);
}

确保未命名名称空间中的函数不会在使用ADL的模板中找到的唯一方法是将其设置为静态。

为现代c++更新

从c++ '11开始,未命名命名空间的成员隐式具有内部链接(3.5/4):

未命名的名称空间或在未命名的名称空间中直接或间接声明的名称空间具有内部链接。

但与此同时,14.6.4.2/1被更新,删除了链接(这来自c++ '14):

对于后缀表达式是依赖名称的函数调用,候选函数使用 通常的查找规则(3.4.1,3.4.2),除了: 对于使用非限定名称查找的部分(3.4.1),只找到模板定义上下文中的函数声明。 对于使用关联名称空间的查找部分(3.4.2),只会找到在模板定义上下文或模板实例化上下文中找到的函数声明。

结果是静态名称空间成员和未命名名称空间成员之间的这种特殊区别不再存在。

就我个人而言,我更喜欢静态函数而不是无名称的名称空间,原因如下:

It's obvious and clear from function definition alone that it's private to the translation unit where it's compiled. With nameless namespace you might need to scroll and search to see if a function is in a namespace. Functions in namespaces might be treated as extern by some (older) compilers. In VS2017 they are still extern. For this reason even if a function is in nameless namespace you might still want to mark them static. Static functions behave very similar in C or C++, while nameless namespaces are obviously C++ only. nameless namespaces also add extra level in indentation and I don't like that :)

所以,我很高兴看到静态函数不再被弃用了。

c++ 98标准不赞成为此目的使用static关键字。静态的问题在于它不适用于类型定义。它也是一个重载关键字,在不同的上下文中以不同的方式使用,因此未命名的名称空间简化了一些事情。

我刚才在看你的问题时才了解到这个特点,我只能猜测。这似乎比文件级静态变量提供了几个优势:

匿名名称空间可以嵌套在另一个名称空间中,提供多级保护,使符号无法逃脱。 可以在同一个源文件中放置多个匿名名称空间,从而在同一个文件中创建不同的静态级作用域。

我想知道是否有人在实际代码中使用过匿名名称空间。