从模板父类访问继承的变量

时间:2009-03-03 08:03:29

标签: c++ inheritance templates

请考虑以下代码:

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接受它,(至少)旧的Intel和SGI c ++编译器也是如此。

新的Gnu C ++编译器是否符合标准?如果他们这样做,继承类背后的基本原理是什么,无法看到受保护的继承成员变量?

另外,如果有

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的成员函数中使用它时。 我发现这也很奇怪:Bar继承了Foo,所以我认为Bar的范围内的A()显然是Foo :: A()。

2 个答案:

答案 0 :(得分:38)

后来的GCC版本正确实现了该标准。

该标准指定模板中的非限定名称是非依赖的,必须在定义模板时查找。那时依赖基类的定义是未知的(可能存在基类模板的特化),因此无法解析非限定名称。

对于在基类中声明的变量和函数名称都是如此。

如您所见,解决方案是提供变量或函数的限定名称,或提供“使用”声明。 E.g。

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%确定使用版本的正确语法,不能从这里进行测试,但是你明白了。)

答案 1 :(得分:4)

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; b.g();
}

GCC将在基类f中的f(t)中查找A<T>,并在基类中找到声明。 GCC之所以这样,是因为f依赖,因为f的参数“依赖于模板参数”(查看它给你的错误信息!)。但标准禁止海湾合作委员会这样做有两个原因

  1. 标准规定,无论名称是否依赖,使用非限定名称都不会在依赖基类中找到声明。

  2. 标准表示在实例化时依赖查找函数名称只能执行ADL。

  3. GCC 4.7在这方面正确实施了标准。