C++11/14/17,GCC 7 与 GCC 8:好友类模板的名称查找

C++11/14/17, GCC 7 vs GCC 8: Name lookup for friend class templates

本文关键字:GCC 查找 好友 C++11      更新时间:2023-10-16

我试图弄清楚以下代码在GCC 7中有效,但在GCC 8.1中无效。

代码的作用是:

  • 定义(并转发声明(类模板MyGoodFriend(在全局命名空间中(
  • 定义inner命名空间内Befriended类模板
  • MyGoodFriend的所有专业成为Befriended的朋友

有问题的一块是

template<class FA>
friend class MyGoodFriend;

我明白问题是什么。GCC 8.1 要求我在friend声明中使用完全限定的名称::MyGoodFriend- 但是,GCC 7 只对MyGoodFriend感到满意。这是代码:

template<class A>
class MyGoodFriend;
namespace inner {
template<class T>
class Befriended {
private:
int i;
T t;
template<class FA>
friend class MyGoodFriend;
// This works for gcc 8.1:
// template<class FA>
//friend class ::MyGoodFriend;
};
} // namespace inner
template<class A>
class MyGoodFriend {
public:
void do_something() {
inner::Befriended<bool> bf;
bf.i = 42;
}
};
int main() {
MyGoodFriend<int> mgf;
mgf.do_something();
}

您可以在此处使用 GCC 7 与 8 进行测试:https://godbolt.org/g/6u9rgy

两个问题:

为什么海湾合作委员会的行为发生了变化?

GCC 7是否误解了标准?或者这是 GCC 8 中的一个错误?

如果GCC 8是正确的:为什么?

如果我正确阅读了标准(请参阅此处的 C++14 标准(: 第 3.4 节(指定名称查找的工作原理(,第 7.4 点指出:

定义 X 类中使用的名称 [...]

  • 如果 X 是命名空间 N 的成员,或者是 是 N 的成员,或者是本地类或本地中的嵌套类 作为 N 成员的函数的类,在定义之前 命名空间 N 中的类 X 或 N 的封闭命名空间之一

显然,MyGoodFriend是在封闭命名空间中声明的,因此它应该在Befriended中可见 - 对吧?

感谢您的任何帮助!

来自 [namespace.memdef]/3,强调我的(C++11 中的措辞相同(:

如果非本地类中的友元声明首先声明类、函数

、类模板或函数模板99,则该友元是最内层封闭命名空间的成员。[...]如果友元声明中的名称既不是限定的也不是模板 ID,并且声明是一个函数或详细类型说明符,则用于确定实体是否已先前声明的查找不应考虑最内层封闭命名空间之外的任何范围

也就是说,当您编写:

template<class FA>
friend class MyGoodFriend;

我们只寻找inner::MyGoodFriend,而不是::MyGoodFriend。由于我们找不到它,我们认为它是类模板inner::MyGoodFriend的前向声明。因此,::MyGoodFriend不是friend编辑。


随着修订版,gcc 7 的编译可能是因为许多与模板访问相关的错误之一。看到这个元错误。GCC 8的行为是正确的。