关于c ++:GCC问题:使用依赖于模板参数的基类成员

关于c ++:GCC问题:使用依赖于模板参数的基类成员

GCC issue: using a member of a base class that depends on a template argument

以下代码不使用gcc编译,但使用Visual Studio编译:

1
2
3
4
5
6
7
8
9
template <typename T> class A {
public:
    T foo;
};

template <typename T> class B: public A < T > {
public:
    void bar() { cout << foo << endl; }
};

我收到错误:

test.cpp: In member function ‘void B::bar()’:

test.cpp:11: error: ‘foo’ was not declared in this scope

但它应该是! 如果我将bar更改为

1
void bar() { cout << this->foo << endl; }

然后它确实编译,但我不认为我必须这样做。 GCC在这里遵循C ++官方规范中的某些内容,还是仅仅是一个怪癖?


大卫·乔伊纳有历史,这就是原因。

编译B< T >时的问题是它的基类A< T >在编译器中是未知的,是一个模板类,所以编译器无法知道基类中的任何成员。

早期版本通过实际解析基本模板类做了一些推断,但ISO C ++声明这种推断可能导致不应该存在的冲突。

在模板中引用基类成员的解决方案是使用this(与您一样)或专门命名基类:

1
2
3
4
5
6
7
8
9
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 ++永远不会因为它的古怪而让我感到惊讶。

In a template definition, unqualified names will no longer find members of a dependent base (as specified by [temp.dep]/3 in the C++ standard). For example,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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
  }
};

You must make the names dependent, e.g. by prefixing them with this->. Here is the corrected definition of C::h,

1
2
3
4
5
6
7
template <typename T> void C< T >::h ()
{
  this->m = 0;
  this->f ();
  this->n = 0
  this->g ();
}

As an alternative solution (unfortunately not backwards compatible with GCC 3.3), you may use using declarations instead of this->:

1
2
3
4
5
6
7
8
9
10
11
12
13
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 ();
  }
};

这只是各种疯狂。谢谢,大卫。

这是他们所指的标准[ISO / IEC 14882:2003]的"temp.dep / 3"部分:

In the definition of a class template or a member of a class template, if a base class of the class template depends on a template-parameter, the base class scope is not examined during unqualified name lookup either at the point of definition of the class template or member or during an instantiation of the class template or member. [Example:

1
2
3
4
5
6
7
typedef double A;
template<class T> class B {
    typedef int A;
};
template<class T> struct X : B< T > {
    A a; // a has typedouble
};

The type name A in the definition of X< T > binds to the typedef name defined in the global namespace scope, not to the typedef name defined in the base class B< T >. ] [Example:

1
2
3
4
5
6
7
8
9
10
11
12
13
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;

The members A::B, A::a, and A::Y of the template argument A do not affect the binding of names in Y. ]


这在gcc-3.4中有所改变。 C ++解析器在该版本中变得更加严格 - 按照规范,但对于具有传统或多平台代码库的人来说仍然有点烦人。


C ++在这里不能假设的主要原因是基本模板可以在以后专门用于某种类型。继续原始的例子:

1
2
3
4
5
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'。除非你告诉编译器它来自何处,否则在实例化之前它根本无法检查模板的有效性。
这就是为什么你必须告诉编译器它来自哪里。


推荐阅读

    opporeno8参数配置及价格

    opporeno8参数配置及价格,面部,亿元,Oppo的荣誉2020年1月4日,接近屏幕关闭传感器是否支持双卡:支持oppor11splus什么时候上市的Oppo R11S P

    魅蓝note6性能参数有哪些

    魅蓝note6性能参数有哪些,摄像头,蓝牙,魅蓝note6性能参数有哪些魅力蓝色Note6最好拍照。电池寿命更长。蓝色Note6使用高通 snapdragon 625

    设置总账参数|用友u8设置总账参数

    设置总账参数|用友u8设置总账参数,,1. 用友u8设置总账参数1、首先要点开数据权限控制设置;2、选择想要设置控制的单据;3、打开后看到左上角

    csgo参数设置|csgo怎么保存

    csgo参数设置|csgo怎么保存,,csgo怎么保存第一步下载csgo的官方版本。然后再下载一个5e对战平台,PS:5e的账号和csgo的账号不是一个账号。第

    移动apn设置|移动apn设置参数

    移动apn设置|移动apn设置参数,,移动apn设置参数1、打开手机系统设置界面应用,点击页面中的“移动网络”设置选项。2、进入移动网络设置页面

    均线最佳设置|均线最佳参数设置

    均线最佳设置|均线最佳参数设置,,1. 均线最佳参数设置所有指标包括kd macd均线,是根据已有价格计算得出,看指标落后于看价格分析,也就是k线。

    viv0nex参数配置|viv0x60参数

    viv0nex参数配置|viv0x60参数,,1. viv0nex参数配置运行内存:6GB机身容量:128GB电池类型:锂聚合物电池2. viv0x60参数没有15+256,所谓的15是内存