gcc 错误?名称隐藏与派生类中具有相同名称的类模板的专门化,但仅当基类也是模板时

问题描述 投票:0回答:1

下面显示的错误消息是 gcc 13.1.0 bug 吗? 此代码在 clang 18.0.2 和 MSVC 19.41 下编译良好。 如果将

s0
更改为非模板类,此代码甚至可以在 gcc 上编译正常。
s0
作为一个模板类,有一些特殊之处让 gcc 感到不安。

目标是派生类

s1
应该有自己的类模板
foo
,它完全隐藏来自
foo
的任何
s0
。 然后在声明
foo
后,
s1
还想指定
s1::foo<T>
s1
的好友。 看起来 gcc 将
s1
的第一行解释为
s0<int>::foo<T>
的部分特化,但同样(奇怪的是)只有当
s0
是模板类时。

template< class X >
struct s0
{
    template< class T >
    struct foo;
};
struct s1 : public s0<int>
{
    // - this should be an entirely new class template "foo"
    // - hiding the "foo" in s0<int>
    // [basic.scope.hiding]
    //
    template< class T >
    struct foo;

    // - gcc error is:
    // partial specialization 's0<int>::foo<T>' declared 'friend'
    // (gcc thinks the line above is a partial specialization??)
    //
    template< class T >
    friend
    struct foo;
};

如果这是一个错误,有什么解决方法吗?

c++ scope language-lawyer name-lookup name-hiding
1个回答
0
投票

好的,感谢@Jarod42、@3CxEZiVlQ 和@user17732522,我们在不查看 gcc 源代码的情况下得到了尽可能多的答案:

  1. 首先,
    friend
    是不必要的,因为嵌套类已经是其包含类的隐式友元。耶! 删除永远是最好的解决方案。
  2. 但是对于像我这样仍然对神秘错误消息感到好奇的人来说,见解是:
    • friend
      声明中查找名称的范围不是
      s1
      类范围,而是“最内部的封闭命名空间范围”(dcl.meaning.general.2.3)。 因此,
      friend
      第二行上的
      s1
      声明将“直接查看”
      foo
      中新符号
      s1
      的任何声明。 事实上,如果删除
      s1
      的第一行,错误仍然存在。
    • 规范措辞“最内层封闭命名空间范围”建议 gcc 应该在全局范围内查找
      foo
      ,而全局范围中没有
      foo
      ,但实际上从编译器错误消息中我们可以看到 gcc 认为我们正在尝试到
      friend
      专业化
      s0<int>::foo<T>
      ,因此 gcc 显然正在寻找
      s0
      。 不确定这是否正确,但是 basic.lookup.unqual 中有一个非规范注释说“当搜索类范围时,也会搜索其基类的范围([class.member.lookup ])。 如果它继承自单个基类,则就好像基类的范围立即包含派生类的范围,”这可以证明 gcc 的选择是合理的(但不是规范性的)。在澄清它的规范?
    • 真的不知道为什么 gcc 会抱怨专门化(因为
      friend
      声明没有声明任何专门化,如 this 相关的,修复了有关注入类名的 gcc bug 中提到的)。 也许这可能只是一个错误的诊断,可能与将 foo
       名称巧妙(错误)解释为 
      s0<int>::foo<T>
       并将其视为与
      这个答案中类似(但不相同)的方式有关。
© www.soinside.com 2019 - 2024. All rights reserved.