C++11/14/17,GCC 7 与 GCC 8:朋友 class 模板的名称查找
C++11/14/17, GCC 7 vs GCC 8: Name lookup for friend class templates
我想知道以下代码在 GCC 7 中是否有效,但在 GCC 8.1 中无效。
代码的作用是:
- 定义(并向前声明)一个 class 模板
MyGoodFriend
(在全局命名空间中)
- 在
inner
命名空间 中定义一个 class 模板 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 的行为发生了变化?
GCC 7 是否误解了标准?或者这是 GCC 8 中的错误?
如果 GCC 8 是正确的:为什么?
如果我没看错标准(这里指的是C++14标准):
第 3.4 节(指定名称查找的工作方式),第 7.4 点指出:
A name used in the definition of a class X […]
- if X is a member of namespace N, or is a nested class of a class that
is a member of N, or is a local class or a nested class within a local
class of a function that is a member of N, before the definition of
class X in namespace N or in one of N ’s enclosing namespaces
显然,MyGoodFriend
是在封闭的命名空间中声明的,因此它应该在 Befriended
中可见 - 对吗?
感谢您的帮助!
来自[namespace.memdef]/3,强调我的(C++11中的措辞相同):
If a friend declaration in a non-local class first declares a class, function, class template or function template99 the friend is a member of the innermost enclosing namespace. [...] If the name in a friend declaration is neither qualified nor a template-id and the declaration is a function or an elaborated-type-specifier, the lookup to determine whether the entity has been previously declared shall not consider any scopes outside the innermost enclosing namespace.
也就是你写的时候:
template<class FA>
friend class MyGoodFriend;
我们只寻找 inner::MyGoodFriend
,而不寻找 ::MyGoodFriend
。由于我们没有找到它,我们认为它是 class 模板 inner::MyGoodFriend
的前向声明。因此,::MyGoodFriend
未被 friend
编辑。
通过修订,gcc 7 编译可能是因为许多与模板访问相关的错误之一。看到这个 meta-bug。 gcc 8 的行为是正确的。
我想知道以下代码在 GCC 7 中是否有效,但在 GCC 8.1 中无效。
代码的作用是:
- 定义(并向前声明)一个 class 模板
MyGoodFriend
(在全局命名空间中) - 在
inner
命名空间 中定义一个 class 模板 - 使
MyGoodFriend
的所有专长成为Befriended
的好友
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 的行为发生了变化?
GCC 7 是否误解了标准?或者这是 GCC 8 中的错误?
如果 GCC 8 是正确的:为什么?
如果我没看错标准(这里指的是C++14标准): 第 3.4 节(指定名称查找的工作方式),第 7.4 点指出:
A name used in the definition of a class X […]
- if X is a member of namespace N, or is a nested class of a class that is a member of N, or is a local class or a nested class within a local class of a function that is a member of N, before the definition of class X in namespace N or in one of N ’s enclosing namespaces
显然,MyGoodFriend
是在封闭的命名空间中声明的,因此它应该在 Befriended
中可见 - 对吗?
感谢您的帮助!
来自[namespace.memdef]/3,强调我的(C++11中的措辞相同):
If a friend declaration in a non-local class first declares a class, function, class template or function template99 the friend is a member of the innermost enclosing namespace. [...] If the name in a friend declaration is neither qualified nor a template-id and the declaration is a function or an elaborated-type-specifier, the lookup to determine whether the entity has been previously declared shall not consider any scopes outside the innermost enclosing namespace.
也就是你写的时候:
template<class FA>
friend class MyGoodFriend;
我们只寻找 inner::MyGoodFriend
,而不寻找 ::MyGoodFriend
。由于我们没有找到它,我们认为它是 class 模板 inner::MyGoodFriend
的前向声明。因此,::MyGoodFriend
未被 friend
编辑。
通过修订,gcc 7 编译可能是因为许多与模板访问相关的错误之一。看到这个 meta-bug。 gcc 8 的行为是正确的。