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

CRTP and visibility of a type that is defined by the base class

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

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() { }

它沿用了前面的示例,尽管稍作修改。
模板参数已添加到基础 class,派生参数已相应更新。
这个不编译。

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 应该是基础 class 的一部分,因此对派生对象可见,就像第一个示例中发生的那样。

它遵循一个例子,根据我对问题的猜测,实际编译但不应该,或者至少应该像前一个一样:

template <typename T>
struct B {
    using foo = T;
};

struct D: public B<int> {
    static foo bar;
};

int main() {
    B<int> *b = new D;
}

会不会是因为派生的 class 在这种情况下不是模板化的?
老实说,这在我看来有点奇怪,因为 foo 类型是基础 class 的一部分,它仍然是模板化的,所以它应该与前一个没有太大区别。

不言而喻,我错了,但我想不出我的想法有什么问题。

提前感谢您的帮助。

那是因为名称查找规则。如果你的 base class 是一个模板,那么 base 中的非限定名称不会被解析。原因是稍后在您的代码中,您可能有该基的模板特化,它没有定义名称,或者名称的含义完全不同。对于编译器来说太复杂了,无法弄清楚你是否有专业化,如果有,你的名字在其中的含义是否相同。所以它更愿意推迟名称查找。要使编译器 "believe you",则需要使用限定名称,或者使用 this->name(对于成员,而不是 typedef),编译器将解析该名称。