GCC 问题:使用依赖于模板参数的基类成员
以下代码不能使用 gcc 编译,但可以使用 Visual Studio 编译:
template <typename T> class A {
public:
T foo;
};
template <typename T> class B: public A <T> {
public:
void bar() { cout << foo << endl; }
};
我收到错误:
test.cpp:在成员函数'void B::bar()'中:
test.cpp:11: 错误:'foo' 未在此范围内声明
但它应该是! 如果我将 bar
更改为,
void bar() { cout << this->foo << endl; }
那么它会编译,但我认为我不必这样做。 GCC 是否遵循 C++ 官方规范中的某些内容,或者这只是一个怪癖?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
大卫·乔伊纳有过这样的历史,原因如下。
编译
B
时的问题是编译器无法识别其基类A
,它是一个模板类,因此编译器无法知道来自基类的任何成员。早期版本通过实际解析基模板类来进行一些推理,但 ISO C++ 表示这种推理可能会导致不应该发生的冲突。
在模板中引用基类成员的解决方案是使用
this
(就像您所做的那样)或专门命名基类:更多信息请参见 gcc 手册。
David Joyner had the history, here is the reason.
The problem when compiling
B<T>
is that its base classA<T>
is unknown from the compiler, being a template class, so no way for the compiler to know any members from the base class.Earlier versions did some inference by actually parsing the base template class, but ISO C++ stated that this inference can lead to conflicts where there should not be.
The solution to reference a base class member in a template is to use
this
(like you did) or specifically name the base class:More information in gcc manual.
哇。 C++ 的怪异总是让我感到惊讶。
这太疯狂了。 谢谢,大卫。
这是他们引用的标准 [ISO/IEC 14882:2003] 的“temp.dep/3”部分:
Wow. C++ never ceases to surprise me with its weirdness.
That's just all kinds of crazy. Thanks, David.
Here's the "temp.dep/3" section of the standard [ISO/IEC 14882:2003] that they are referring to:
这在 gcc-3.4 中发生了变化。 C++ 解析器在该版本中变得更加严格——根据规范,但对于拥有遗留或多平台代码库的人来说仍然有点烦人。
This changed in gcc-3.4. The C++ parser got much more strict in that release -- per the spec but still kinda annoying for people with legacy or multi-platform code bases.
C++ 在这里不能假设任何事情的主要原因是基础模板可以稍后专门用于某种类型。 继续原来的例子:
The main reason C++ cannot assume anything here is that the base template can be specialized for a type later. Continuing the original example:
VC 没有实现两阶段查找,而 GCC 实现了。 因此,GCC 在实例化模板之前对其进行解析,因此比 VC 发现更多错误。
在您的示例中, foo 是一个从属名称,因为它依赖于“T”。 除非您告诉编译器它来自哪里,否则它在实例化模板之前根本无法检查模板的有效性。
这就是为什么你必须告诉编译器它来自哪里。
VC doesn't implemented two-phase lookup, while GCC does. So GCC parses templates before they are instantiated and thus finds more errors than VC.
In your example, foo is a dependent name, since it depends on 'T'. Unless you tell the compiler where it comes from, it cannot check the validity of the template at all, before you instantiate it.
That's why you have to tell the compiler where it comes from.