【问题标题】:Accessing inherited variable from templated parent class [duplicate]从模板化父类访问继承的变量[重复]
【发布时间】:2010-10-10 23:14:03
【问题描述】:

考虑以下代码:

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()。

【问题讨论】:

    标签: c++ inheritance templates


    【解决方案1】:

    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 将在基类A&lt;T&gt; 中的f(t) 中查找f,并将在基类中找到声明。 GCC 这样做是因为 f 是依赖的,因为 f 的参数“依赖于模板参数”(看看它给你的错误消息!)。但标准禁止 GCC 这样做有两个原因

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

    2. 标准规定在实例化时对函数名的依赖查找只会执行 ADL。

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

    【讨论】:

      【解决方案2】:

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

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

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

      正如您所观察到的,解决方案是提供变量或函数的限定名称,或者提供“使用”声明。例如

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

      【讨论】:

      • 谢谢。我要撸起袖子改代码了。
      • 我相信你必须在类级别做 using 语句,即模板 Bar : public Foo { using Foo::a; ... };
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多