使用 CRTP 时的可见性问题

Visibility problems when using CRTP

这是我能想出的一个最小示例:

template <typename T>
struct Util
{
    using Type = int;
};

struct A
{
    struct B : public Util<B> {
        void fun(Type) {}
    };
};

template <typename T>
struct C
{
    struct D : public Util<D> {
        void fun(Type) {}
    };
};

int main()
{
    A::B{}.fun(0);
    C<int>::D{}.fun(0);
}

A::BC::D 之间的唯一区别是 C 是一个模板。

结构 C::D 编译失败,出现以下错误:

test_cpp.cpp:18:18: error: ‘Type’ has not been declared
         void fun(Type) {}
                  ^~~~

为什么编译失败?我该如何编译?

假设 Util 来自外部库,我无法更改它(如果你有兴趣,它是 boost::iterator_facade)。

此时:

template <typename T>
struct C
{
    struct D : public Util<D> {
        void fun(Type) {} // <-- here
    };
};

编译器无法知道 * Type 需要来自Util<D> 的范围。这与调用基 class 成员函数的问题相同,需要用 this-> 明确限定,否则将找不到它们。

您应该能够通过显式限定类型来解决此问题:

void fun(typename Util<D>::Type) {}

参见complete snippet on Coliru

差异背后的原因是,正如@etam1024 在评论中正确指出的那样,在 A::B 中,Type 是一个非依赖名称,而在 C::D 中它是从属名称。有关基本 class 成员函数 this answer.

的成员函数限定的类似情况的解释,请参见

* 在我看来,编译器 可以 知道在哪里寻找 Type,但是语言规则说它不会找那么远。请注意,我可能忽略了编译器无法推断出这一点的特殊情况,因此导致需要完全 koalafication 的一般情况。