嵌套在函数中的函数声明的命名空间 [英] Namespace of a function declaration nested in function

查看:56
本文介绍了嵌套在函数中的函数声明的命名空间的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

出于奇怪的原因,我想在函数范围内声明一个函数.所以我得到以下代码:

For odd reasons, I want to declare a function inside a function scope. So I get the following code :

namespace NS
{
    void foo()
    {
        void bar();
        bar();
    }
}

在另一个编译单元中,我要定义栏.根据我使用的编译器,我需要将bar放在名称空间NS或全局名称空间中才能链接:

In another compilation unit, I want to define bar. Depending on the compiler I'm using, I need to put bar in namespace NS or in the global namespace to be able to link:

在叮当声中:

namespace NS
{
    void bar() {}
}

在MSVC上:

void bar() {}

有什么好的行为?

作为一个附带的问题,以下代码为何都不能编译(在我的2个编译器上):

As a side question, why is none of the following code compiling (on my 2 compilers):

namespace NS
{
    void foo()
    {
        void bar();
        ::bar(); // bar declared in global namespace
    }
}

namespace NS
{
    void foo()
    {
        void bar();
        ::NS::bar(); // bar declared in NS namespace
    }
}

谢谢您的帮助.

GiSylbe

推荐答案

注意:长话短说; msvc 做错了,而 clang 是正确的.这篇文章将通过显示相关摘要并使用标准引号来支持索赔来说明原因.

Note: Long story, short; msvc is doing it wrong, and clang is correct. This post will explain why by showing relevant snippets, and having standard quotations to back up the claims.

关于第一个代码段/问题


简介

据说块作用域中的函数声明是指最内部封闭的命名空间中的实体,因此在下面的 bar 中是指 NS :: bar .

namespace NS {
  void foo () {
    void bar (); // (A), forward-declaration of `NS::bar`

    bar ();      // call (A)
  }
}

这意味着您在定义 bar 时必须在名称空间 N 中或使用 qualified-id 进行引用到所述实体.

This means that you, upon defining bar, must do so in either namespace N, or by using a qualified-id to refer to said entity.

void f ():     // some other `void f()`;  _not_ (A)

void NS::f (); // same `f` as being declared at (A)

namespace NS {
  void f ();   // same `f` as being declared at (A)
}


标准怎么说?( n3337 )

3.5p6 程序和链接 [basic.link]

在块作用域中声明的函数名称与在块作用域 extern 声明中声明的变量名称具有链接.如果存在具有相同名称和类型的链接的实体的可见声明,而忽略在最内层封闭的命名空间范围之外声明的实体,则块范围声明将声明相同的实体,并接收先前声明的链接.如果有多个这样的匹配实体,则程序格式错误.否则,如果找不到匹配的实体,则块作用域实体将接收外部链接.

The name of a function declared in block scope and the name of a variale declared by a block scope extern declaration have linkage. If there is a visible declaration of an enity with linkage having the same name and type, ignoring entities declared outside the innermost enclosing namespace scope, the block scope declaration declares the same entitiy and receives the linkage of the previous declaration. If there is more than one such matching entity, the program is ill-formed. Otherwise, if no matching entity is found, the block scope entity receives external linkage.


结论

msvc 做错了, clang 显示的行为是正确的.


Conclusion

msvc is doing it wrong, the behavior shown by clang is the correct one.

遇到块范围声明时,它引用的是最接近的封闭名称空间中的实体,但不会在该名称空间中引入这样的名称.

When a block-scope declaration is encountered it is referring to an entity in the closest enclosing namespace, but it does not introduce such name in that namespace.

3.5p7 程序和链接 [basic.link]

当未发现具有链接的实体的块作用域声明引用其他某个声明时,则该实体是最内部封闭的命名空间的成员.但是,这样的声明不会在其名称空间范围内引入成员名称.

When a block scope declaration of an entity with linkage is not found to refer to some other declaration, then that entity is a member of the innermost enclosing namespace. However such a declaration does not introduce the member name in its namespace scope.

请参见以下示例:

namespace NS {
  void foo() {
    void bar();  // (A), forward-declaration of `NS::bar`
    ::NS::bar(); //      ill-formed, there is no `::NS::bar` yet
    bar ();      //           legal, call the `bar` being forward-declared by (A)
  }
}

在上面的(A)中引用了即将出现的 :: NS :: bar 声明,但是由于前向声明不会使 namespace NS 具有实体名为 bar 的实体,我们只能通过 bar 引用被称为 :: NS :: bar 的实体.

In the above (A) refers to an upcoming declaration of ::NS::bar, but since a forward-declaration does not make namespace NS have an entity named bar we can only refer to the entity that will be known as ::NS::bar through bar.

void bar ();    // (A), `::bar`

namespace NS {
  void foo() {
    void bar();   // (B), forward-declaration of `NS::bar`

    ::bar();      // call (A)
    bar ();       // call (B), `NS::bar`

    ::NS::bar (); // ill-formed, `namespace NS` doesn't have an entity named bar (yet) 
  }

  void bar ();    // (C), make `NS` have an entity named bar, this is the one
                  //      being referred to by (B)

  void baz () {
    ::NS::bar (); // legal, `namespace NS` now have an entity named `bar`, as being
                  //        declared in (C)
  }
}

这篇关于嵌套在函数中的函数声明的命名空间的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆