出于奇怪的原因,我想在函数范围内声明一个函数。 所以我得到以下代码:
namespace NS
{
void foo()
{
void bar();
bar();
}
}
在另一个编译单元中,我想定义bar。 根据我使用的编译器,我需要将 bar 放在命名空间 NS 或全局命名空间中以便能够链接:
在 clang 中:
namespace NS
{
void bar() {}
}
在 MSVC 上:
void bar() {}
什么是好的行为,如果有的话?
作为附带问题,为什么以下代码都没有编译(在我的 2 个编译器上):
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
}
}
感谢您的帮助。
吉西尔贝
最佳答案
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.
关于第一个片段/问题
简介
block 作用域中的函数声明被称为引用最内层封闭命名空间中的实体,因此在下面的 bar 中引用 NS::bar。
namespace NS {
void foo () {
void bar (); // (A), forward-declaration of `NS::bar`
bar (); // call (A)
}
}
这意味着您在定义 bar 时,必须在命名空间 N 中执行此操作,或者使用 qualified-id 来引用给所述实体。
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
Program and linkage[basic.link]
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
显示的行为是正确的。
关于第二个片段/问题
说明
当遇到 block 作用域声明时,它指的是最近的封闭命名空间中的实体,但它不会在该命名空间中引入这样的名称。
3.5p7
Program and linkage[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
的实体。
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)
}
}
关于c++ - 嵌套在函数中的函数声明的命名空间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24239846/