c - 未命名/匿名的namespaces和静态函数直接的区别

  显示原文与译文双语对照的内容

C++ little-used的特点是能够创建匿名( 匿名) 名称空间,就像这样:


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

你会认为这种特性将是无用的--因为你不能指定命名空间的名称,是不可能从外部访问任何在它。 但这些不知名的名称空间访问在文件中创建的,如果你有一个隐式 using-clause 。

我的问题是,为什么还是什么时候使用静态函数更可取? 还是本质上是两种方法来完成完全相同的事情?

时间:

C++ 标准读取节 7.3.1.1 未命名名称空间,段落 2:

在命名空间作用域中声明对象时,不使用静态关键字,unnamed-namespace提供了一个更好的替代方法。

静态只适用于对象,函数和匿名联合的名称,而不适用于类型声明。

编辑:

拒绝这里使用静态关键字( 影响翻译单元中变量声明的可见性)的决定已经被反转( 参考 ) 。 在这种情况下,使用静态名称空间或者未命名名称空间实际上是两种执行完全相同操作的方法。 有关更多讨论,请参见这个类。

未命名的命名空间仍然具有允许你定义translation-unit-local类型的优点。 请查看这个,以便更多细节。

感谢 。Percy,让我注意到。

有一个边缘情况,其中静态的影响( 至少对我来说) 。 C++03标准状态在 14.6.4.2/1 中:

对于函数取决于模板参数,如果函数名称是 unqualified-id 而不是 template-id,候选函数的调用被发现使用的常用的查找规则( 3.4.1,3.4.2 ) 除了︰

  • 对于使用非限定名称查找( 3.4.1 )的查找部分,只找到来自模板定义上下文外部链接的函数声明。
  • 对于使用关联命名空间( 3.4.2 )的查找部分,在tmeplate定义上下文或者模板实例化上下文中找到了只有外部链接的函数声明。

下面的代码将调用 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++ 编译器( IE 。 一个支持 exportstatic 关键字,关键字仍然具有其他任何方式不可用的功能。


//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的模板中找到未命名名称空间中的函数的唯一方法是使它的成为 static

查看这个综合示例来理解匿名名称空间和静态变量之间的区别例如:

查看一个示例:

这是 file1.cpp


#include<iostream>
using namespace std;

namespace
{
 int local;
}

void func();

int main()
{
 local = 1;
 cout <<"Local=" <<local <<endl;
 func();
 cout <<"Local=" <<local <<endl;
 return 0;
}

/* 这是 file2.cpp */


namespace
{
//Should not collide with other files
 int local;
}

void func()
{
 local = 2;
}

注意:你需要同时包含同一个项目中的文件。

这里程序的结果应该是:

本地= 1

本地= 1

如果使用静态变量而不是匿名名称空间,输出将是=

本地= 1

本地= 2

...