朋友类,继承和typedef - 哪种行为是正确的?

Nik*_*tov 8 c++ gcc clang

我偶然发现了一个错误,它只出现在GCC 6.2.0上,而不是出现在Clang 3.9.0上(都在-std=c++14模式下).我不确定哪种行为是正确的(以及我是否应该提交错误).

这是代码:

template<typename type_t>
class foo_t
{
};

class bar_t
{
public:
    using foo_t = int;
};

class baz_t:
    public bar_t
{
private:
    template<typename type_t>
    friend class foo_t;
};
Run Code Online (Sandbox Code Playgroud)

在GCC上,这会出现以下错误:

test.cpp:17:15: error: using typedef-name ‘using foo_t = int’ after ‘class’
  friend class foo_t;
               ^~~~~
test.cpp:9:19: note: ‘using foo_t = int’ has a previous declaration here
  using foo_t = int;
                   ^
Run Code Online (Sandbox Code Playgroud)

根据我所知的C++标准,父级typedef(或usings)不应泄漏到子级的范围内,您需要明确限定名称:例如,请参阅将"typedef"从基于"模板"的派生类传播到"模板".所以在我看来,GCC在这里是不正确的,但我不太确定我的C++知识可以自信地说.

谢谢你的帮助!

Rei*_*ica 4

根据我对 C++ 标准的了解,父级typedef(或using父级)不应泄漏到子级的范围中,并且您需要显式限定名称

这是不正确的。基类中声明的成员(包括类型别名)通常在派生类中可见。您链接到的问题专门涉及具有依赖基类的模板,其中适用两阶段名称查找(同样,适用于所有内容,而不仅仅是类型别名)。

除此之外,标准的相关部分是 C++14 (N4140) [dcl.type.elab] 7.1.6.3/2 (强调我的):

3.4.4 描述了如何对详细类型说明符中的标识符进行名称查找。如果标识符 解析为类名枚举名,详细类型说明符将其引入声明中,就像简单类型说明符引入其类型名一样。如果标识符解析为typedef-namesimple-template-id解析为别名模板特化,则详细类型说明符格式错误。

(注意:详细类型说明符是我们正在处理的class T某些类型的构造)。T

3.4.4 反过来说,当将详细类型说明符中的标识符解析为名称时,非类型名称将被忽略(但通常会找到类型名称)。

foo_t因此,GCC 实际上是正确的,因为作用域中的typedef-namebar_t比全局作用域 template-name 的作用域“更接近” foo_tfoo_t因此,内部的非限定名称baz_t解析为bar_t::foo_t,它是一个typedef 名称,因此使得详细类型说明符格式错误。

问题在于不合格名称的解析foo_t。正如您在问题评论中指出的那样,明确说明foo_t您的意思应该解决问题:

tempalte <typename type_t>
friend class ::foo_t;
Run Code Online (Sandbox Code Playgroud)