这里是一个工作代码的简短示例。这有助于介绍实际问题
可见性的说明符与实际代码中使用的相同
class Base {
public:
using foo = int;
virtual ~Base() { }
protected:
static foo bar() noexcept {
static foo v = 0;
return v++;
}
};
template<class Derived>
class Class: public Base {
static foo get() noexcept {
static foo v = bar();
return v;
}
};
int main() { }
它沿用了前面的示例,尽管略有修改
已经向基类添加了一个模板参数,并且相应地更新了派生的参数
这个不能编译。
template<typename T>
class Base {
public:
using foo = int;
virtual ~Base() { }
protected:
static foo bar() noexcept {
static foo v = 0;
return v++;
}
};
template<class Derived, typename T>
class Class: public Base<T> {
static foo get() noexcept {
static foo v = bar();
return v;
}
};
int main() { }
错误确实很明显,问题不是要解决它:
main.cpp:18:12: error: ‘foo’ does not name a type
static foo get() noexcept {
^
main.cpp:18:12: note: (perhaps ‘typename BaseComponent<T>::foo’ was intended)
实际的问题是:为什么在第二个示例中,如果没有作用域说明符,foo
就不可见
我的意思是,Class
是从Base<T>
派生的,也就是(至少在我看来)一个完全定义的类型,因此foo
应该是基类的一部分,因此对派生的基类可见,就像第一个例子中发生的那样。
它遵循了一个例子,根据我对问题的猜测,它实际上是编译的,不应该,或者至少应该像前一个一样:
template <typename T>
struct B {
using foo = T;
};
struct D: public B<int> {
static foo bar;
};
int main() {
B<int> *b = new D;
}
在这种情况下,可能是因为派生类不是模板化的吗
老实说,这在我看来有点奇怪,因为foo
类型是基类的一部分,它仍然是一个模板化的基类,所以它应该与前一个没有太大区别。
不用说我错了,但我无法弄清楚自己的想法出了什么问题
提前感谢您的帮助。
这是因为名称查找规则。如果基类是一个模板,则不会解析基类中不合格的名称。原因是,稍后在代码中,您可能会对该基础进行模板专门化,该基础没有定义名称,或者名称的含义完全不同。编译器太复杂了,无法判断你是否有专门化,如果有,你的名字在里面的意思是否相同。所以它更喜欢推迟名字查找。为了让编译器"相信你",你需要使用一个限定名称,或者使用this->name
(对于成员,而不是typedef),编译器将解析该名称。