CRTP和基类定义的类型的可见性



这里是一个工作代码的简短示例。这有助于介绍实际问题
可见性的说明符与实际代码中使用的相同

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),编译器将解析该名称。

最新更新