7

使用 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必要?

4

3 回答 3

7

这两个代码都是无效的(只有最后一个是有效的),但你的编译器(不符合)只诊断一个。正如另一个答案所说,这使用注入的类名。一个类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<int>格式错误,因为它使用注入的类名,但是无法访问。如果您使用 GCC less 4.5,它可能与 GCC4.5引入的更改有关:

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将引用数据-成员。

于 2010-07-12T07:36:40.237 回答
3

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

::在您的 typedef 中使用before运算符S将告诉您的编译器不要使用S您继承的,而是S在全局命名空间中使用。

请参阅此链接

于 2010-07-12T04:11:01.433 回答
0

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

于 2010-07-12T03:50:57.453 回答