由于奇怪的原因,我想在函数范围内声明一个函数。 所以我得到以下代码:
namespace NS
{
void foo()
{
void bar();
bar();
}
}
在另一个编译单元中,我想定义bar。 根据我正在使用的编译器,我需要将bar放在命名空间NS或全局命名空间中以便能够链接:
On 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
}
}
感谢您的帮助。
GiSylbe
答案 0 :(得分:1)
注意:长篇故事,简短; msvc 做错了, clang 是正确的。这篇文章将解释为什么通过显示相关的片段,并使用标准报价来支持声明。
块作用域中的函数声明被称为最内层封闭命名空间中的实体,因此在下面的栏中指的是 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)
}
3.5p6
计划和关联[basic.link]
块作用域中声明的函数的名称和块作用域
extern
声明声明的变量的名称具有链接。如果存在具有相同名称和类型的链接的enity的可见声明,忽略在最内部封闭命名空间范围之外声明的实体,则块范围声明声明相同的权限并接收先前声明的链接。如果存在多个这样的匹配实体,则该程序是不正确的。否则,如果未找到匹配的实体,则块范围实体将接收外部链接。
msvc
做错了,clang
显示的行为是正确的。
当遇到块范围声明时,它指的是最近的封闭命名空间中的实体,但不在该命名空间中引入此类名称。
3.5p7
计划和关联[basic.link]
当找不到具有链接的实体的块范围声明来引用其他声明时,该实体是最内层封闭命名空间的成员。但是,这样的声明不会在其命名空间范围内引入成员名称。
见下面的例子:
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
声明,但由于前向声明不使名称空间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)
}
}