代码之家  ›  专栏  ›  技术社区  ›  Paul J. Lucas

错误的私有基类不可访问?

  •  7
  • Paul J. Lucas  · 技术社区  · 14 年前

    使用G++4.2.1编译此代码:

    struct S { };
    template<typename T> struct ST { };
    
    template<typename BaseType>
    class ref_count : private BaseType { };
    
    template<typename RefCountType>
    class rep_base : public RefCountType { };
    
    class wrap_rep : public rep_base<ref_count<S> > {
      typedef rep_base<ref_count<S> > base_type;      // line 11
    };
    

    我得到:

    bug.cpp:1: error: ‘struct S’ is inaccessible
    bug.cpp:11: error: within this context
    

    但是,如果我改变 wrap_rep 使用类 ST :

    class wrap_rep : public rep_base<ref_count< ST<int> > > {
      typedef rep_base<ref_count< ST<int> > > base_type;
    };
    

    它编译得很好。或者,如果我将原始代码更改为:

    class wrap_rep : public rep_base<ref_count<S> > {
      typedef rep_base<ref_count< ::S > > base_type;  // now using ::
    };
    

    它也编译得很好。对我来说,原始代码看起来很好。这是G++错误吗?如果没有,那么为什么使用模板有效呢?另一种情况是,为什么 ::S 必要吗?

    3 回复  |  直到 12 年前
        1
  •  7
  •   Johannes Schaub - litb    14 年前

    这两个代码都是无效的(只有最后一个有效),但您的编译器(不一致)只诊断一个。正如另一个答案所说,它使用注入的类名。一个班 S 被认为具有成员名称 S 表示同一类。例如(注意前面的“class”关键字 S::S 在第一个示例中,需要强制引用注入的类名,而不是默认的构造函数):

    class S { };
    
    class S::S object; // creates an S object
    class X : S::S::S::S { }; // derives from class S
    

    类模板还具有注入的类名。与注入的类名一样,它继承到派生类,因此 ST<int> 格式错误,因为它使用了注入的类名,但无法访问。如果您使用的GCC小于4.5,它可能与 change introduced Gcc4.5:

    G++现在实现了dr 176。以前G++不支持将模板基类的注入类名用作类型名,查找该名称时在封闭范围中找到了模板的声明。现在,查找名称会找到注入的类名,根据名称后面是否跟有模板参数列表,可以将其用作类型或模板。由于此更改,以前接受的某些代码可能格式错误,因为

    1. 无法访问注入的类名,因为它来自私有基,或者
    2. 注入的类名不能用作模板模板参数的参数。

    在这两种情况下,可以通过添加嵌套的名称说明符来显式命名模板来修复代码。第一个可以与-fno访问控制一起使用;第二个只能用-pedantic拒绝。


    为了让注入的类名更有趣一点,请注意注入的类名并不象人们可能首先想到的那样等价于typedef。注入的类名是类名,但不属于typedef名称,这意味着它可以被函数、对象或枚举器名称隐藏:

    // valid, the data-member hides the injected class name
    struct S { int S; };
    

    要引用注入的类名,可以说 class S::S (同样,在基类列表中,非类型名被忽略,因此您不需要特别的预先警告),只需简单地查找 S:: 将引用数据成员。

        2
  •  3
  •   Bertrand Marron    14 年前

    你的结构 S 是的基类 wrap_rep 这意味着它被注入 拉普瑞普 好像有一个匿名typedef。

    使用操作员 :: 之前 S 在typedef中,将告诉编译器不要使用 S 你继承自,但是 S 在全局命名空间中。

    this link .

        3
  •  0
  •   Jagannath    14 年前

    在“Sun WorkWord 6更新2编译器C++”中编译好了原始代码。这是我在办公室里唯一能接触到的。可以在您拥有的任何其他编译器上进行尝试。