为什么C ++编译器不能识别g()
和b
是Superclass
的继承成员,如下面的代码所示:
template<typename T> struct Superclass {
protected:
int b;
void g() {}
};
template<typename T> struct Subclass : public Superclass<T> {
void f() {
g(); // compiler error: uncategorized
b = 3; // compiler error: unrecognized
}
};
如果我简化Subclass
并且只是从Subclass<int>
继承,那么它就会编译。当完全限定g()
为Superclass<T>::g()
和Superclass<T>::b
时,它也会编译。我正在使用LLVM GCC 4.2。
注意:如果我在超类中公开g()
和b
,它仍然会失败并出现相同的错误。
答案 0 :(得分:47)
可以使用using
:
template<typename T> struct Subclass : public Superclass<T> {
using Superclass<T>::b;
using Superclass<T>::g;
void f() {
g();
b = 3;
}
};
或者通过this
指针访问来限定名称:
template<typename T> struct Subclass : public Superclass<T> {
void f() {
this->g();
this->b = 3;
}
};
或者,正如您已经注意到的那样,通过限定全名。
这是必要的原因是C ++不考虑超类模板进行名称解析(因为它们是依赖名称,并且不考虑依赖名称)。它在您使用Superclass<int>
时有效,因为它不是模板(它是模板的实例化),因此其嵌套名称不是依赖名称。
答案 1 :(得分:14)
Konrad的回答并没有要求或回答所有这些中的最终“为什么”。这不仅仅是C ++委员会随意说“嘿,放弃依赖的名字,无论如何都没有人喜欢它们”。相反,编译器甚至在它们被实例化之前就对模板进行了一些检查,并且在它知道T之前它不能理解g()或b,因为它不能 - 通常 - 在可能的特化之间进行选择。基类(例如SuperClass<X>
可能有int b
而SuperClass<Y>
有void b()
而SuperClass<Z>
根本没有b
。更明确的形式只是说“相信我 - 这必须来自实例化时的基类(否则会有编译器错误)”。