从模板父类访问inheritancevariables
考虑下面的代码:
template<class T> class Foo { public: Foo() { a = 1; } protected: int a; }; template<class T> class Bar : public Foo<T> { public: Bar() { b = 4; }; int Perna(int u); protected: int b; }; template<class T> int Bar<T>::Perna(int u) { int c = Foo<T>::a * 4; // This works return (a + b) * u; // This doesn't }
g ++ 3.4.6,4.3.2和4.1.2给出错误
test.cpp: In member function `int Bar<T>::Perna(int)': test.cpp:25: error: `a' was not declared in this scope
g ++ 2.96和MSVC 6,7,7.1,8和9接受它,至less是旧的Intel和SGI c ++编译器。
新的Gnu C ++编译器是否遵守标准? 如果他们这样做,inheritance类的基本原理是不能看到一个受保护的inheritance成员variables?
另外,如果有的话
int A() { return a; }
在Foo,我得到错误
test.cpp:25: error: there are no arguments to A that depend on a template parameter, so a declaration of A must be available test.cpp:25: error: (if you use -fpermissiveâ, G++ will accept your code, but allowing the use of an undeclared name is deprecated)
当我尝试在Bar的成员函数中使用它。 我也觉得好奇:BarinheritanceFoo,所以我认为Bar的范围A()显然是Foo :: A()。
后来的GCC版本正确地执行标准。
该标准指定模板中的非限定名称是非相关的,在定义模板时必须查找。 当时,依赖基类的定义是未知的(基类模板的专业化可能存在),所以不合格的名称无法parsing。
对于在基类中声明的variables名和函数名都是如此。
正如你所看到的解决scheme是提供variables或函数的限定名称,或提供“使用”声明。 例如
template<class T> int Bar<T>::Perna(int u) { int c = Foo<T>::a * 4; // This works c = this->a * 4; // and this using Foo<T>::a; c = a * 4; // and with 'using', so should this }
(我实际上不是100%确定正确的使用版本的语法,不能从这里testing,但你明白了)。
GCC给出的错误信息表明您的GCC版本仍然存在一个仅在GCC4.7中继版本中解决的错误。 旧版本,包括GCC4.1将高兴地接受以下代码
template<typename T> struct A { void f(int) { } }; template<typename T> struct B : A<T> { void g() { T t = 0; f(t); } }; int main() { B<int> b; bg(); }
GCC会在基类A<T>
内的f(t)
查找f
,并在基类中find该声明。 GCC做到这一点是因为f
是依赖的 ,因为有f
参数,“依赖于模板参数”(看看它给你的错误信息!)。 但标准禁止海湾合作委员会这样做有两个原因
-
该标准指出,使用非限定名称将永远不会在依赖基类中find声明, 无论名称是否依赖 。
-
该标准说,在实例化的时候对函数名称的依赖查询只会执行ADL。
GCC 4.7在这方面正确地执行了标准。