【问题标题】:Erroneous private base class inaccessible?错误的私有基类无法访问?
【发布时间】:2011-03-14 15:08:45
【问题描述】:

使用 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

【问题讨论】:

    标签: c++ private base-class name-lookup private-inheritance


    【解决方案1】:

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

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

    类模板也有一个注入的类名。像注入的类名一样,它被继承到派生类,因此ST&lt;int&gt; 是格式错误的,因为它使用了注入的类名,但它是不可访问的。如果你使用 GCC less 4.5,它可能与 GCC4.5 的 change introduced 有关:

    G++ 现在实现了 DR 176。以前 G++ 不支持使用模板基类的注入类名称作为类型名称,并且查找名称会在封闭范围内找到模板的声明。现在查找名称会找到注入的类名称,它可以用作类型或模板,具体取决于名称后面是否有模板参数列表。由于这一变化,一些以前被接受的代码可能是格式错误的,因为

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

    在任何一种情况下,都可以通过添加嵌套名称说明符来显式命名模板来修复代码。第一个可以使用 -fno-access-control 解决;第二个只被 -pedantic 拒绝。


    为了让注入的类名更有趣 - 请注意注入的类名并不像人们首先想到的那样等同于 typedef。注入的类名是类名,但不归类为typedef-name,也就是说它可以被函数、对象或枚举器名隐藏:

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

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

    【讨论】:

      【解决方案2】:

      您的结构 Swrap_rep 的基类,这意味着它被注入到 wrap_rep 中,就好像有一个匿名 typedef。

      在 typedef 中在 S 之前使用运算符 :: 会告诉编译器不要使用继承自的 S,而是在全局命名空间中使用 S

      this link

      【讨论】:

        【解决方案3】:

        原始代码在“Sun WorkShop 6 update 2 Compilers C++”中编译良好。这是我办公室里唯一可以接触到的。可以尝试使用您拥有的任何其他编译器。

        【讨论】:

          猜你喜欢
          • 2013-09-09
          • 2011-11-04
          • 2014-01-10
          • 2020-05-09
          • 1970-01-01
          • 2015-04-18
          • 1970-01-01
          • 2012-05-13
          相关资源
          最近更新 更多