使用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
是必要的?
答案 0 :(得分: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减去4.5,它可能与change introduced与GCC4.5有关:
G ++现在实现DR 176.以前G ++不支持使用模板基类的inject-class-name作为类型名称,并且查找名称在封闭范围内找到模板的声明。现在查找名称会找到inject-class-name,它可以用作类型或模板,具体取决于名称后面是否有模板参数列表。由于此更改,以前接受的某些代码可能格式不正确,因为
- 无法访问inject-class-name,因为它来自私有基础,或
- inject-name-name不能用作模板模板参数的参数。
醇>在这两种情况中,可以通过添加嵌套名称说明符来明确命名模板来修复代码。第一个可以使用-fno-access-control解决;第二个只是被拒绝了。
为了让注入的类名更有趣 - 请注意注入的类名不等于首先想到的typedef。注入的类名是类名,但不归类为typedef-name,这意味着它可以被函数,对象或枚举器名称隐藏:
// valid, the data-member hides the injected class name
struct S { int S; };
要引用注入的类名,您可以说class S::S
(同样,在基类列表中,忽略非类型名称,因此您不需要特别的注意事项),但是很简单查找到S::S
将引用数据成员。
答案 1 :(得分:3)
你的结构S
是wrap_rep
的基类,这意味着它被注入wrap_rep
,好像有一个匿名的typedef。
在typedef中使用::
之前的运算符S
将告诉编译器不要使用您继承的S
,而是使用全局命名空间中的S
。
请参阅this link。
答案 2 :(得分:0)
原始代码在“Sun WorkShop 6 update 2 Compilers C ++”中编译得很好。这是我在办公室里唯一可以访问的。可以试试你拥有的任何其他编译器。