如何解决哪些规范性文本规定了在非ADL查找中只能在封闭的名称空间中声明一次重新才能找到一个在类中定义的朋友? 问题朋友声明无论是否定义不会在封闭的名称空间中引入新名称
下面的所有标准参考均引用N4659: March 2017 post-Kona working draft/C++17 DIS。
声明为好友的函数也可以在好友声明中定义,如下所示:
#include <iostream>
namespace a {
struct A {
// DeFinition of 'a::foo()'
friend void foo() { std::cout << __PRETTY_FUNCTION__; }
};
} // namespace a
诸如a::foo()
之类的功能(有时称为“隐藏的朋友”)无法通过不合格或合格的查找来找到:
int main() {
a::foo(); // error: no member named 'foo' in namespace 'a'
}
根据[basic.lookup.argdep]/4可以找到,但是可以通过ADL [强调我的]:
考虑关联命名空间时,查找与 当关联的名称空间用作 限定符([namespace.qual]),除了:
专门基于ADL定义的类类型:
#include <iostream>
namespace a {
struct A {
friend void foo(const A&) { std::cout << __PRETTY_FUNCTION__; }
};
} // namespace a
int main() {
foo(a::A{}); // void a::foo(const a::A &)
}
但是,如果我们在定义它的类的名称空间范围内(重新)声明该函数,则可以通过限定/不限定查找来找到该函数:
#include <iostream>
namespace a {
struct A {
friend void foo() { std::cout << __PRETTY_FUNCTION__; }
};
void foo();
} // namespace a
int main() {
a::foo(); // void a::foo()
}
问题
解决方法
下面的所有标准参考,除非另有明确说明,请参考N4659: March 2017 post-Kona working draft/C++17 DIS。
朋友声明(无论是否定义)不会在封闭的名称空间中引入新名称
[class.friend]/6控制“隐藏的朋友”的范围(仅在其朋友声明中声明和定义)[强调我的]:
[class.friend] / 6:当且仅当该类是非本地类([class.local])时,才可以在该类的朋友声明中定义一个函数,函数名称不合格,且函数具有名称空间范围。
因此,即使函数的定义位于其朋友声明中,该朋友函数也具有名称空间范围,并且可以通过(在其所在类的)命名空间中的(重新)声明来显式地进行常规查找。已定义。)
#include <iostream>
namespace a {
struct A {
// Definition of 'a::foo()' (note the namespace scope).
friend void foo() { std::cout << __PRETTY_FUNCTION__; }
};
// (re-)declaration of foo().
void foo();
} // namespace 'a'
int main() {
a::foo(); // void a::foo()
}
但是,要问的更普遍和有趣的问题是
- 什么决定了朋友声明不将声明的名称引入/绑定到命名空间范围?
哪个受[namespace.memdef]/3约束
[namespace.memdef] / 3: 如果在非本地类中的朋友声明,首先声明一个类,函数,类模板或函数模板朋友是最里面的封闭命名空间的成员。朋友声明本身不会使名称显示给不合格的查找([basic.lookup.unqual])或合格的查找([basic.lookup.qual])。 [注意: 如果在名称空间范围内提供了匹配的声明,则朋友的名称将在其名称空间中可见(在授予友谊的类定义之前或之后)。 —注释] [...]
因此,此处的功能不是在好友声明中定义,而是在好友声明(即使不包含定义)中也不会将名称引入名称空间范围;在以下示例中,查找同样无法从好友声明中找到名称:
#include <iostream>
namespace a {
struct A {
friend void bar();
};
} // namespace 'a'
int main() {
a::bar(); // error: no member named 'bar' in namespace 'a'
}
我们还可能注意到,C ++ 20草案N4861( 2020年3月布拉格后工作草案/ C ++ 20 DIS )添加了一个段落,尽管不是规范,明确提到这一点;来自[basic.scope.pdecl]/13 [强调我的]:
[注意:朋友声明是指最近的封闭命名空间成员的函数或类,但它们不会在该命名空间中引入新名称([命名空间。 memdef])。 [...]
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。