以下代码不使用gcc编译,但使用Visual Studio编译:
templateclass A { public: T foo; }; template class B: public A { public: void bar() { cout << foo << endl; } };
我收到错误:
test.cpp:在成员函数'void B :: bar()'中:
test.cpp:11:错误:在此范围内未声明'foo'
但它应该是!如果我换bar
到
void bar() { cout << this->foo << endl; }
然后它确实编译,但我不认为我必须这样做.GCC在这里遵循C++官方规范中的某些内容,还是仅仅是一个怪癖?
大卫·乔伊纳有历史,这就是原因.
编译时的问题B
是它的基类A
在编译器中是未知的,是一个模板类,所以编译器无法知道基类中的任何成员.
早期版本通过实际解析基本模板类做了一些推断,但ISO C++声明这种推断可能导致不应该存在的冲突.
在模板中引用基类成员的解决方案是使用this
(像您一样)或专门命名基类:
templateclass A { public: T foo; }; template class B: public A { public: void bar() { cout << A ::foo << endl; } };
有关gcc手册的更多信息.
哇.C++永远不会因为它的古怪而让我感到惊讶.
在模板定义中,非限定名称将不再找到依赖库的成员(由C++标准中的[temp.dep]/3指定).例如,
templatestruct B { int m; int n; int f (); int g (); }; int n; int g (); template struct C : B { void h () { m = 0; // error f (); // error n = 0; // ::n is modified g (); // ::g is called } };
您必须使名称依赖,例如通过在其前面加上this->.这是C :: h的更正定义,
templatevoid C ::h () { this->m = 0; this->f (); this->n = 0 this->g (); }
作为替代解决方案(遗憾的是不向后兼容GCC 3.3),您可以使用声明而不是this->:
templatestruct C : B { using B ::m; using B ::f; using B ::n; using B ::g; void h () { m = 0; f (); n = 0; g (); } };
这只是各种疯狂.谢谢,大卫.
这是他们所指的标准[ISO/IEC 14882:2003]的"temp.dep/3"部分:
在类模板的定义或类模板的成员中,如果类模板的基类依赖于模板参数,则在类的定义时,在非限定名称查找期间不会检查基类作用域.模板或成员或在类模板或成员的实例化期间.[例:
typedef double A; templateclass B { typedef int A; }; template struct X : B { A a; // a has typedouble };
A
定义中的类型名称X
绑定到全局命名空间范围中定义的typedef名称,而不绑定到基类中定义的typedef名称B
.] [例子:
struct A { struct B { /* ... */ }; int a; int Y; }; int a; templatestruct Y : T { struct B { /* ... */ }; B b; //The B defined in Y void f(int i) { a = i; } // ::a Y* p; // Y }; Y ya;
这在gcc-3.4中有所改变.C++解析器在该版本中变得更加严格 - 按照规范,但对于具有传统或多平台代码库的人来说仍然有点烦人.
C++在这里不能假设的主要原因是基本模板可以在以后专门用于某种类型.继续原始的例子:
template<> class A{}; B x; x.bar();//this will fail because there is no member foo in A