【发布时间】:2018-06-13 15:46:26
【问题描述】:
我试图弄清楚以下代码在 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 vs 8 进行测试:https://godbolt.org/g/6u9rgy
两个问题:
为什么 GCC 的行为发生了变化?
GCC 7 是否误解了标准?或者这是 GCC 8 中的一个错误?
如果 GCC 8 是正确的:为什么?
如果我正确阅读了标准(这里指的是 C++14 标准): 第 3.4 节(指定名称查找的工作方式)第 7.4 点指出:
X 类定义中使用的名称 […]
- 如果 X 是命名空间 N 的成员,或者是某个类的嵌套类 是 N 的成员,或者是本地类或本地内的嵌套类 作为 N 成员的函数的类,在定义之前 命名空间 N 或 N 的封闭命名空间之一中的类 X
显然,MyGoodFriend 是在封闭的命名空间中声明的,因此它应该在 Befriended 中可见 - 对吧?
感谢您的帮助!
【问题讨论】:
-
几个月前我见过类似的东西。
-
在您的示例中,我看不出 gcc 7 和 8 之间的行为有什么不同?
-
@Barry 哦,是的,对不起!我简化了我的示例,使其不再使用 GCC 7 进行编译。关键是
Befriended类也需要是一个模板。我更改了上面的代码!