当前位置:  开发笔记 > 编程语言 > 正文

未命名/匿名命名空间与静态函数

如何解决《未命名/匿名命名空间与静态函数》经验,为你挑选了6个好方法。

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

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

您会认为这样的功能是无用的 - 因为您无法指定命名空间的名称,所以无法从外部访问其中的任何内容.但是这些未命名命名空间可以在它们创建的文件访问,就好像你有一个隐含的using子句.

我的问题是,为什么或何时使用静态函数会更好?或者他们基本上是两种做同样事情的方式?



1> luke..:

C++标准在第7.3.1.1节"未命名的命名空间"中进行了介绍,第2段:

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

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

编辑:

弃用static关键字的这种使用(影响翻译单元中变量声明的可见性)的决定已被颠倒(ref).在这种情况下,使用静态或未命名的命名空间基本上是两种完全相同的方式.有关更多讨论,请参阅此 SO问题.

未命名的命名空间仍然具有允许您定义翻译单元本地类型的优点.有关更多详细信息,请参阅此 SO问题.

幸得迈克·珀西提出这个引起我的注意.


Head Geek询问仅针对函数使用的静态关键字.应用于在命名空间作用域中声明的实体的static关键字指定其内部链接.在匿名名称空间中声明的实体具有外部链接(C++/3.5),但是它保证存在于唯一命名的作用域中.这种匿名的无名空间有效地隐藏了它的声明,使其只能从翻译单元中访问.后者有效地以与static关键字相同的方式工作.
因为这个答案在Google上作为"c ++匿名命名空间"的最高结果出现,所以应该注意静态的使用不再被弃用.请参阅http://stackoverflow.com/questions/4726570/deprecation-of-the-static-keyword-no-more和http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html #1012了解更多信息.
在C++设计组合中,那些静态关键字被弃用的人可能从未在大型真实世界系统中使用过庞大的C代码......(如果它包含很多带有大量注释的声明,你可以立即看到静态关键字而不是匿名命名空间块).
外部联动的缺点是什么?这会影响内联吗?
@ErikAronesty为什么?

2> hazzen..:

将方法放在匿名命名空间中可以防止您意外违反" 一个定义规则",从而使您永远不必担心命名助手方法与您可能链接的其他方法相同.

而且,正如luke所指出的,匿名命名空间是静态成员的标准首选.


我指的是静态独立功能(即文件作用域函数),而不是静态成员函数。静态独立功能与未命名空间中的功能非常相似,因此是个问题。
啊; 好吧,ODR仍然适用.编辑删除段落.

3> Richard Cord..:

有一个边缘情况静态具有惊人的效果(至少对我而言).C++ 03标准在14.6.4.2/1中声明:

对于依赖于模板参数的函数调用,如果函数名称是unqualified-id但不是template-id,则使用通常的查找规则(3.4.1,3.4.2)找到候选函数,除了:

对于使用非限定名称查找(3.4.1)的查找部分,仅找到具有来自模板定义上下文的外部链接的函数声明.

对于使用关联命名空间(3.4.2)的查找部分,仅找到在模板定义上下文或模板实例化上下文中找到的具有外部链接的函数声明.

...

以下代码将调用foo(void*)而不是foo(S const &)您所期望的.

template 
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++编译器(即支持export),该static关键字仍然具有其他方式无法使用的功能.

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

// bar.cc
#include "bar.h"
template 
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.

更新现代C++

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

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

但与此同时,更新了14.6.4.2/1以删除链接的提及(这取自C++ '14):

对于postfix-expression是从属名称的函数调用,使用通常的查找规则(3.4.1,3.4.2)找到候选函数,除了:

对于使用非限定名称查找(3.4.1)的查找部分,仅找到模板定义上下文中的函数声明.

对于使用关联命名空间(3.4.2)的查找部分,仅找到在模板定义上下文或模板实例化上下文中找到的函数声明.

结果是静态和未命名的命名空间成员之间的这种特殊差异不再存在.


导出关键字是不应该冷死?唯一支持"出口"的编译器是实验性的,除非出现意外,否则"出口"甚至不会在其他情况下实施,因为出现了意想不到的副作用(此外还没有预期)
爱迪生设计集团(EDG)的前端不过是实验性的.它几乎可以肯定是世界上最符合标准的C++实现.英特尔C++编译器使用EDG.
参见Herb Sutter关于子喷气的文章:http://www.gotw.ca/publications/mill23-x.htm

4> 小智..:

我最近开始在我的代码中用匿名命名空间替换静态关键字,但是立即遇到了一个问题,即命名空间中的变量不再可用于我的调试器中进行检查.我使用的是VC60,所以我不知道这是否与其他调试器没有问题.我的解决方法是定义一个"模块"命名空间,在那里我给它命名了我的cpp文件.

例如,在我的XmlUtil.cpp文件中,我为所有模块变量和函数定义了一个名称空间XmlUtil_I {...}.这样我就可以在调试器中应用XmlUtil_I :: qualified来访问变量.在这种情况下,'_ I'将它与我可能想在别处使用的公共名称空间(如XmlUtil)区分开来.

我认为与真正的匿名方法相比,这种方法的潜在缺点是,有人可能通过在其他模块中使用命名空间限定符来违反所需的静态范围.我不知道这是否是一个主要问题.


我也是这样做的,但使用`#if DEBUG命名空间BlahBlah_private {#else namespace {#endif`,所以"模块命名空间"只出现在调试版本中,否则会使用真正的匿名命名空间.如果调试器提供了一个很好的方法来处理它,那将是很好的.Doxygen也被它弄糊涂了.
未命名的命名空间实际上不是静态的替代品.静态意味着"真的,这永远不会与TU联系在一起".未命名的命名空间意味着"它仍然作为随机名称导出,以防它从TU之外的父类调用"...

5> Firas Assaad..:

C++ 98标准不推荐使用static关键字.static的问题在于它不适用于类型定义.它也是在不同上下文中以不同方式使用的重载关键字,因此未命名的命名空间简化了一些事情.


你会想,不是吗?但是,如果同一个应用程序中的另一个转换单元(= cpp-file)声明了一个具有相同名称的类型,那么您将面临相当难以调试的问题:-).例如,您最终可能会遇到在调用另一个类型的方法时使用其中一个类型的vtable的情况.

6> Don Wakefiel..:

根据经验,我只会注意到,虽然将以前的静态函数放入匿名命名空间是C++方式,但是较旧的编译器有时会遇到问题.我目前正在为我们的目标平台使用一些编译器,而更现代的Linux编译器可以将函数放入匿名命名空间.

但是在Solaris上运行的较旧的编译器,我们将在未指定的未来版本中使用,有时会接受它,有时会将其标记为错误.错误不是让我担心的问题,而是接受它时它可能正在做的事情.因此,在我们全面展现现代之前,我们仍然使用静态(通常是类范围的)函数,我们更喜欢匿名命名空间.

推荐阅读
135369一生真爱_890
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有