下面的代码不会用gcc编译,但与Visual Studio的功能:
template <typename T> class A {
public:
T foo;
};
template <typename T> class B: public A <T> {
public:
void bar() { cout << foo << endl; }
};
我得到的错误:
TEST.CPP:在构件函数 'void B :: bar()的':
TEST.CPP:11:错误:“富”在此范围未声明
但它应该是! 如果我改变bar
到
void bar() { cout << this->foo << endl; }
然后它编译,但我不认为我必须这样做。 有东西在C的官方规格++中GCC是继在这里,或者是它只是一个怪癖?
这改变了GCC-3.4 。 C ++的语法分析器了在该版本中要严格得多 - 每规范,但仍有点儿讨厌的人与传统或者多平台的代码库。
大卫·乔伊纳有历史,这里的原因。
编译时,问题B<T>
是,它的基类A<T>
是未知的从编译器,作为一个模板类,所以没办法对编译器知道从基类任何成员。
早期版本通过实际解析基本模板类做了一些推测,但ISO C ++指出,这一推断可能导致冲突的地方,不应该有。
在模板中引用一个基类成员的解决办法是使用this
(像你这样)或特别命名的基类:
template <typename T> class A {
public:
T foo;
};
template <typename T> class B: public A <T> {
public:
void bar() { cout << A<T>::foo << endl; }
};
更多信息GCC手册 。
哇。 C ++从未停止其古怪到让我感到吃惊。
在模板中定义,不合格的名称将不再发现从属基的成员(如由[temp.dep]在C ++标准/ 3指定)。 例如,
template <typename T> struct B {
int m;
int n;
int f ();
int g ();
};
int n;
int g ();
template <typename T> struct C : B<T> {
void h ()
{
m = 0; // error
f (); // error
n = 0; // ::n is modified
g (); // ::g is called
}
};
您必须名称相关的,例如用这个 - 他们的前缀>。 下面是Ç::小时校正定义,
template <typename T> void C<T>::h ()
{
this->m = 0;
this->f ();
this->n = 0
this->g ();
}
作为一种替代的解决方案(不幸的是不向后与GCC 3.3兼容),则可以使用使用声明,而不是这 - >:
template <typename T> struct C : B<T> {
using B<T>::m;
using B<T>::f;
using B<T>::n;
using B<T>::g;
void h ()
{
m = 0;
f ();
n = 0;
g ();
}
};
这只是各种疯狂。 谢谢你,大卫。
这里的“temp.dep / 3”标准的[ISO 14882 / IEC:2003]部分,他们指的是:
在一类模板或模板类中的成员的定义,如果一个基类类模板的依赖于模板的参数,不是在类定义的点时不合格的名称查找或者检查的基类范围模板或构件或类模板或部件的实例化期间。 [例:
typedef double A;
template<class T> class B {
typedef int A;
};
template<class T> struct X : B<T> {
A a; // a has typedouble
};
类型名称A
在的定义X<T>
结合于在全局命名空间范围中定义的typedef名称,而不是在基类中定义的typedef名称B<T>
] [实施例:
struct A {
struct B { /* ... */ };
int a;
int Y;
};
int a;
template<class T> struct Y : T {
struct B { /* ... */ };
B b; //The B defined in Y
void f(int i) { a = i; } // ::a
Y* p; // Y<T>
};
Y<A> ya;
成员A::B
, A::a
,和A::Y
模板实参的A
不影响名称的结合Y<A>
。 ]
主要原因C ++不能在这里假设任何事情是基本模板以后可以专门用于一个类型。 继续原来的例子:
template<>
class A<int> {};
B<int> x;
x.bar();//this will fail because there is no member foo in A<int>
VC不执行两阶段查找,而GCC一样。 所以,GCC解析模板它们被实例化,并由此发现更多的错误比VC之前。 在你的榜样,foo是一个从属名称,因为它依赖于“T”。 除非你告诉它从何而来的编译器,它不能检查模板的有效性可言,实例化之前。 这就是为什么你要告诉它从何而来的编译器。
文章来源: GCC issue: using a member of a base class that depends on a template argument